blob: a6664d71621f141f11d0be8f58db2f0fcbd70326 [file] [log] [blame]
henrike@webrtc.orgf0488722014-05-13 18:00:26 +00001/*
2 * Copyright 2004 The WebRTC Project Authors. All rights reserved.
3 *
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
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11#include "webrtc/base/gunit.h"
12#include "webrtc/base/stream.h"
13
14namespace rtc {
15
16///////////////////////////////////////////////////////////////////////////////
17// TestStream
18///////////////////////////////////////////////////////////////////////////////
19
20class TestStream : public StreamInterface {
21 public:
22 TestStream() : pos_(0) { }
23
24 virtual StreamState GetState() const { return SS_OPEN; }
25 virtual StreamResult Read(void* buffer, size_t buffer_len,
26 size_t* read, int* error) {
27 unsigned char* uc_buffer = static_cast<unsigned char*>(buffer);
28 for (size_t i = 0; i < buffer_len; ++i) {
29 uc_buffer[i] = static_cast<unsigned char>(pos_++);
30 }
31 if (read)
32 *read = buffer_len;
33 return SR_SUCCESS;
34 }
35 virtual StreamResult Write(const void* data, size_t data_len,
36 size_t* written, int* error) {
37 if (error)
38 *error = -1;
39 return SR_ERROR;
40 }
41 virtual void Close() { }
42 virtual bool SetPosition(size_t position) {
43 pos_ = position;
44 return true;
45 }
46 virtual bool GetPosition(size_t* position) const {
47 if (position) *position = pos_;
48 return true;
49 }
50 virtual bool GetSize(size_t* size) const {
51 return false;
52 }
53 virtual bool GetAvailable(size_t* size) const {
54 return false;
55 }
56
57 private:
58 size_t pos_;
59};
60
61bool VerifyTestBuffer(unsigned char* buffer, size_t len,
62 unsigned char value) {
63 bool passed = true;
64 for (size_t i = 0; i < len; ++i) {
65 if (buffer[i] != value++) {
66 passed = false;
67 break;
68 }
69 }
70 // Ensure that we don't pass again without re-writing
71 memset(buffer, 0, len);
72 return passed;
73}
74
75void SeekTest(StreamInterface* stream, const unsigned char value) {
76 size_t bytes;
77 unsigned char buffer[13] = { 0 };
78 const size_t kBufSize = sizeof(buffer);
79
80 EXPECT_EQ(stream->Read(buffer, kBufSize, &bytes, NULL), SR_SUCCESS);
81 EXPECT_EQ(bytes, kBufSize);
82 EXPECT_TRUE(VerifyTestBuffer(buffer, kBufSize, value));
83 EXPECT_TRUE(stream->GetPosition(&bytes));
84 EXPECT_EQ(13U, bytes);
85
86 EXPECT_TRUE(stream->SetPosition(7));
87
88 EXPECT_EQ(stream->Read(buffer, kBufSize, &bytes, NULL), SR_SUCCESS);
89 EXPECT_EQ(bytes, kBufSize);
90 EXPECT_TRUE(VerifyTestBuffer(buffer, kBufSize, value + 7));
91 EXPECT_TRUE(stream->GetPosition(&bytes));
92 EXPECT_EQ(20U, bytes);
93}
94
95TEST(StreamSegment, TranslatesPosition) {
96 TestStream* test = new TestStream;
97 // Verify behavior of original stream
98 SeekTest(test, 0);
99 StreamSegment* segment = new StreamSegment(test);
100 // Verify behavior of adapted stream (all values offset by 20)
101 SeekTest(segment, 20);
102 delete segment;
103}
104
105TEST(StreamSegment, SupportsArtificialTermination) {
106 TestStream* test = new TestStream;
107
108 size_t bytes;
109 unsigned char buffer[5000] = { 0 };
110 const size_t kBufSize = sizeof(buffer);
111
112 {
113 StreamInterface* stream = test;
114
115 // Read a lot of bytes
116 EXPECT_EQ(stream->Read(buffer, kBufSize, &bytes, NULL), SR_SUCCESS);
117 EXPECT_EQ(bytes, kBufSize);
118 EXPECT_TRUE(VerifyTestBuffer(buffer, kBufSize, 0));
119
120 // Test seeking far ahead
121 EXPECT_TRUE(stream->SetPosition(12345));
122
123 // Read a bunch more bytes
124 EXPECT_EQ(stream->Read(buffer, kBufSize, &bytes, NULL), SR_SUCCESS);
125 EXPECT_EQ(bytes, kBufSize);
126 EXPECT_TRUE(VerifyTestBuffer(buffer, kBufSize, 12345 % 256));
127 }
128
129 // Create a segment of test stream in range [100,600)
130 EXPECT_TRUE(test->SetPosition(100));
131 StreamSegment* segment = new StreamSegment(test, 500);
132
133 {
134 StreamInterface* stream = segment;
135
136 EXPECT_EQ(stream->Read(buffer, kBufSize, &bytes, NULL), SR_SUCCESS);
137 EXPECT_EQ(500U, bytes);
138 EXPECT_TRUE(VerifyTestBuffer(buffer, 500, 100));
139 EXPECT_EQ(stream->Read(buffer, kBufSize, &bytes, NULL), SR_EOS);
140
141 // Test seeking past "end" of stream
142 EXPECT_FALSE(stream->SetPosition(12345));
143 EXPECT_FALSE(stream->SetPosition(501));
144
145 // Test seeking to end (edge case)
146 EXPECT_TRUE(stream->SetPosition(500));
147 EXPECT_EQ(stream->Read(buffer, kBufSize, &bytes, NULL), SR_EOS);
148
149 // Test seeking to start
150 EXPECT_TRUE(stream->SetPosition(0));
151 EXPECT_EQ(stream->Read(buffer, kBufSize, &bytes, NULL), SR_SUCCESS);
152 EXPECT_EQ(500U, bytes);
153 EXPECT_TRUE(VerifyTestBuffer(buffer, 500, 100));
154 EXPECT_EQ(stream->Read(buffer, kBufSize, &bytes, NULL), SR_EOS);
155 }
156
157 delete segment;
158}
159
160TEST(FifoBufferTest, TestAll) {
161 const size_t kSize = 16;
162 const char in[kSize * 2 + 1] = "0123456789ABCDEFGHIJKLMNOPQRSTUV";
163 char out[kSize * 2];
164 void* p;
165 const void* q;
166 size_t bytes;
167 FifoBuffer buf(kSize);
168 StreamInterface* stream = &buf;
169
170 // Test assumptions about base state
171 EXPECT_EQ(SS_OPEN, stream->GetState());
172 EXPECT_EQ(SR_BLOCK, stream->Read(out, kSize, &bytes, NULL));
173 EXPECT_TRUE(NULL != stream->GetReadData(&bytes));
174 EXPECT_EQ((size_t)0, bytes);
175 stream->ConsumeReadData(0);
176 EXPECT_TRUE(NULL != stream->GetWriteBuffer(&bytes));
177 EXPECT_EQ(kSize, bytes);
178 stream->ConsumeWriteBuffer(0);
179
180 // Try a full write
181 EXPECT_EQ(SR_SUCCESS, stream->Write(in, kSize, &bytes, NULL));
182 EXPECT_EQ(kSize, bytes);
183
184 // Try a write that should block
185 EXPECT_EQ(SR_BLOCK, stream->Write(in, kSize, &bytes, NULL));
186
187 // Try a full read
188 EXPECT_EQ(SR_SUCCESS, stream->Read(out, kSize, &bytes, NULL));
189 EXPECT_EQ(kSize, bytes);
190 EXPECT_EQ(0, memcmp(in, out, kSize));
191
192 // Try a read that should block
193 EXPECT_EQ(SR_BLOCK, stream->Read(out, kSize, &bytes, NULL));
194
195 // Try a too-big write
196 EXPECT_EQ(SR_SUCCESS, stream->Write(in, kSize * 2, &bytes, NULL));
197 EXPECT_EQ(bytes, kSize);
198
199 // Try a too-big read
200 EXPECT_EQ(SR_SUCCESS, stream->Read(out, kSize * 2, &bytes, NULL));
201 EXPECT_EQ(kSize, bytes);
202 EXPECT_EQ(0, memcmp(in, out, kSize));
203
204 // Try some small writes and reads
205 EXPECT_EQ(SR_SUCCESS, stream->Write(in, kSize / 2, &bytes, NULL));
206 EXPECT_EQ(kSize / 2, bytes);
207 EXPECT_EQ(SR_SUCCESS, stream->Read(out, kSize / 2, &bytes, NULL));
208 EXPECT_EQ(kSize / 2, bytes);
209 EXPECT_EQ(0, memcmp(in, out, kSize / 2));
210 EXPECT_EQ(SR_SUCCESS, stream->Write(in, kSize / 2, &bytes, NULL));
211 EXPECT_EQ(kSize / 2, bytes);
212 EXPECT_EQ(SR_SUCCESS, stream->Write(in, kSize / 2, &bytes, NULL));
213 EXPECT_EQ(kSize / 2, bytes);
214 EXPECT_EQ(SR_SUCCESS, stream->Read(out, kSize / 2, &bytes, NULL));
215 EXPECT_EQ(kSize / 2, bytes);
216 EXPECT_EQ(0, memcmp(in, out, kSize / 2));
217 EXPECT_EQ(SR_SUCCESS, stream->Read(out, kSize / 2, &bytes, NULL));
218 EXPECT_EQ(kSize / 2, bytes);
219 EXPECT_EQ(0, memcmp(in, out, kSize / 2));
220
221 // Try wraparound reads and writes in the following pattern
222 // WWWWWWWWWWWW.... 0123456789AB....
223 // RRRRRRRRXXXX.... ........89AB....
224 // WWWW....XXXXWWWW 4567....89AB0123
225 // XXXX....RRRRXXXX 4567........0123
226 // XXXXWWWWWWWWXXXX 4567012345670123
227 // RRRRXXXXXXXXRRRR ....01234567....
228 // ....RRRRRRRR.... ................
229 EXPECT_EQ(SR_SUCCESS, stream->Write(in, kSize * 3 / 4, &bytes, NULL));
230 EXPECT_EQ(kSize * 3 / 4, bytes);
231 EXPECT_EQ(SR_SUCCESS, stream->Read(out, kSize / 2, &bytes, NULL));
232 EXPECT_EQ(kSize / 2, bytes);
233 EXPECT_EQ(0, memcmp(in, out, kSize / 2));
234 EXPECT_EQ(SR_SUCCESS, stream->Write(in, kSize / 2, &bytes, NULL));
235 EXPECT_EQ(kSize / 2, bytes);
236 EXPECT_EQ(SR_SUCCESS, stream->Read(out, kSize / 4, &bytes, NULL));
237 EXPECT_EQ(kSize / 4 , bytes);
238 EXPECT_EQ(0, memcmp(in + kSize / 2, out, kSize / 4));
239 EXPECT_EQ(SR_SUCCESS, stream->Write(in, kSize / 2, &bytes, NULL));
240 EXPECT_EQ(kSize / 2, bytes);
241 EXPECT_EQ(SR_SUCCESS, stream->Read(out, kSize / 2, &bytes, NULL));
242 EXPECT_EQ(kSize / 2 , bytes);
243 EXPECT_EQ(0, memcmp(in, out, kSize / 2));
244 EXPECT_EQ(SR_SUCCESS, stream->Read(out, kSize / 2, &bytes, NULL));
245 EXPECT_EQ(kSize / 2 , bytes);
246 EXPECT_EQ(0, memcmp(in, out, kSize / 2));
247
248 // Use GetWriteBuffer to reset the read_position for the next tests
249 stream->GetWriteBuffer(&bytes);
250 stream->ConsumeWriteBuffer(0);
251
252 // Try using GetReadData to do a full read
253 EXPECT_EQ(SR_SUCCESS, stream->Write(in, kSize, &bytes, NULL));
254 q = stream->GetReadData(&bytes);
255 EXPECT_TRUE(NULL != q);
256 EXPECT_EQ(kSize, bytes);
257 EXPECT_EQ(0, memcmp(q, in, kSize));
258 stream->ConsumeReadData(kSize);
259 EXPECT_EQ(SR_BLOCK, stream->Read(out, kSize, &bytes, NULL));
260
261 // Try using GetReadData to do some small reads
262 EXPECT_EQ(SR_SUCCESS, stream->Write(in, kSize, &bytes, NULL));
263 q = stream->GetReadData(&bytes);
264 EXPECT_TRUE(NULL != q);
265 EXPECT_EQ(kSize, bytes);
266 EXPECT_EQ(0, memcmp(q, in, kSize / 2));
267 stream->ConsumeReadData(kSize / 2);
268 q = stream->GetReadData(&bytes);
269 EXPECT_TRUE(NULL != q);
270 EXPECT_EQ(kSize / 2, bytes);
271 EXPECT_EQ(0, memcmp(q, in + kSize / 2, kSize / 2));
272 stream->ConsumeReadData(kSize / 2);
273 EXPECT_EQ(SR_BLOCK, stream->Read(out, kSize, &bytes, NULL));
274
275 // Try using GetReadData in a wraparound case
276 // WWWWWWWWWWWWWWWW 0123456789ABCDEF
277 // RRRRRRRRRRRRXXXX ............CDEF
278 // WWWWWWWW....XXXX 01234567....CDEF
279 // ............RRRR 01234567........
280 // RRRRRRRR........ ................
281 EXPECT_EQ(SR_SUCCESS, stream->Write(in, kSize, &bytes, NULL));
282 EXPECT_EQ(SR_SUCCESS, stream->Read(out, kSize * 3 / 4, &bytes, NULL));
283 EXPECT_EQ(SR_SUCCESS, stream->Write(in, kSize / 2, &bytes, NULL));
284 q = stream->GetReadData(&bytes);
285 EXPECT_TRUE(NULL != q);
286 EXPECT_EQ(kSize / 4, bytes);
287 EXPECT_EQ(0, memcmp(q, in + kSize * 3 / 4, kSize / 4));
288 stream->ConsumeReadData(kSize / 4);
289 q = stream->GetReadData(&bytes);
290 EXPECT_TRUE(NULL != q);
291 EXPECT_EQ(kSize / 2, bytes);
292 EXPECT_EQ(0, memcmp(q, in, kSize / 2));
293 stream->ConsumeReadData(kSize / 2);
294
295 // Use GetWriteBuffer to reset the read_position for the next tests
296 stream->GetWriteBuffer(&bytes);
297 stream->ConsumeWriteBuffer(0);
298
299 // Try using GetWriteBuffer to do a full write
300 p = stream->GetWriteBuffer(&bytes);
301 EXPECT_TRUE(NULL != p);
302 EXPECT_EQ(kSize, bytes);
303 memcpy(p, in, kSize);
304 stream->ConsumeWriteBuffer(kSize);
305 EXPECT_EQ(SR_SUCCESS, stream->Read(out, kSize, &bytes, NULL));
306 EXPECT_EQ(kSize, bytes);
307 EXPECT_EQ(0, memcmp(in, out, kSize));
308
309 // Try using GetWriteBuffer to do some small writes
310 p = stream->GetWriteBuffer(&bytes);
311 EXPECT_TRUE(NULL != p);
312 EXPECT_EQ(kSize, bytes);
313 memcpy(p, in, kSize / 2);
314 stream->ConsumeWriteBuffer(kSize / 2);
315 p = stream->GetWriteBuffer(&bytes);
316 EXPECT_TRUE(NULL != p);
317 EXPECT_EQ(kSize / 2, bytes);
318 memcpy(p, in + kSize / 2, kSize / 2);
319 stream->ConsumeWriteBuffer(kSize / 2);
320 EXPECT_EQ(SR_SUCCESS, stream->Read(out, kSize, &bytes, NULL));
321 EXPECT_EQ(kSize, bytes);
322 EXPECT_EQ(0, memcmp(in, out, kSize));
323
324 // Try using GetWriteBuffer in a wraparound case
325 // WWWWWWWWWWWW.... 0123456789AB....
326 // RRRRRRRRXXXX.... ........89AB....
327 // ........XXXXWWWW ........89AB0123
328 // WWWW....XXXXXXXX 4567....89AB0123
329 // RRRR....RRRRRRRR ................
330 EXPECT_EQ(SR_SUCCESS, stream->Write(in, kSize * 3 / 4, &bytes, NULL));
331 EXPECT_EQ(SR_SUCCESS, stream->Read(out, kSize / 2, &bytes, NULL));
332 p = stream->GetWriteBuffer(&bytes);
333 EXPECT_TRUE(NULL != p);
334 EXPECT_EQ(kSize / 4, bytes);
335 memcpy(p, in, kSize / 4);
336 stream->ConsumeWriteBuffer(kSize / 4);
337 p = stream->GetWriteBuffer(&bytes);
338 EXPECT_TRUE(NULL != p);
339 EXPECT_EQ(kSize / 2, bytes);
340 memcpy(p, in + kSize / 4, kSize / 4);
341 stream->ConsumeWriteBuffer(kSize / 4);
342 EXPECT_EQ(SR_SUCCESS, stream->Read(out, kSize * 3 / 4, &bytes, NULL));
343 EXPECT_EQ(kSize * 3 / 4, bytes);
344 EXPECT_EQ(0, memcmp(in + kSize / 2, out, kSize / 4));
345 EXPECT_EQ(0, memcmp(in, out + kSize / 4, kSize / 4));
346
347 // Check that the stream is now empty
348 EXPECT_EQ(SR_BLOCK, stream->Read(out, kSize, &bytes, NULL));
349
350 // Try growing the buffer
351 EXPECT_EQ(SR_SUCCESS, stream->Write(in, kSize, &bytes, NULL));
352 EXPECT_EQ(kSize, bytes);
353 EXPECT_TRUE(buf.SetCapacity(kSize * 2));
354 EXPECT_EQ(SR_SUCCESS, stream->Write(in + kSize, kSize, &bytes, NULL));
355 EXPECT_EQ(kSize, bytes);
356 EXPECT_EQ(SR_SUCCESS, stream->Read(out, kSize * 2, &bytes, NULL));
357 EXPECT_EQ(kSize * 2, bytes);
358 EXPECT_EQ(0, memcmp(in, out, kSize * 2));
359
360 // Try shrinking the buffer
361 EXPECT_EQ(SR_SUCCESS, stream->Write(in, kSize, &bytes, NULL));
362 EXPECT_EQ(kSize, bytes);
363 EXPECT_TRUE(buf.SetCapacity(kSize));
364 EXPECT_EQ(SR_BLOCK, stream->Write(in, kSize, &bytes, NULL));
365 EXPECT_EQ(SR_SUCCESS, stream->Read(out, kSize, &bytes, NULL));
366 EXPECT_EQ(kSize, bytes);
367 EXPECT_EQ(0, memcmp(in, out, kSize));
368
369 // Write to the stream, close it, read the remaining bytes
370 EXPECT_EQ(SR_SUCCESS, stream->Write(in, kSize / 2, &bytes, NULL));
371 stream->Close();
372 EXPECT_EQ(SS_CLOSED, stream->GetState());
373 EXPECT_EQ(SR_EOS, stream->Write(in, kSize / 2, &bytes, NULL));
374 EXPECT_EQ(SR_SUCCESS, stream->Read(out, kSize / 2, &bytes, NULL));
375 EXPECT_EQ(0, memcmp(in, out, kSize / 2));
376 EXPECT_EQ(SR_EOS, stream->Read(out, kSize / 2, &bytes, NULL));
377}
378
379TEST(FifoBufferTest, FullBufferCheck) {
380 FifoBuffer buff(10);
381 buff.ConsumeWriteBuffer(10);
382
383 size_t free;
384 EXPECT_TRUE(buff.GetWriteBuffer(&free) != NULL);
385 EXPECT_EQ(0U, free);
386}
387
388TEST(FifoBufferTest, WriteOffsetAndReadOffset) {
389 const size_t kSize = 16;
390 const char in[kSize * 2 + 1] = "0123456789ABCDEFGHIJKLMNOPQRSTUV";
391 char out[kSize * 2];
392 FifoBuffer buf(kSize);
393
394 // Write 14 bytes.
395 EXPECT_EQ(SR_SUCCESS, buf.Write(in, 14, NULL, NULL));
396
397 // Make sure data is in |buf|.
398 size_t buffered;
399 EXPECT_TRUE(buf.GetBuffered(&buffered));
400 EXPECT_EQ(14u, buffered);
401
402 // Read 10 bytes.
403 buf.ConsumeReadData(10);
404
405 // There should be now 12 bytes of available space.
406 size_t remaining;
407 EXPECT_TRUE(buf.GetWriteRemaining(&remaining));
408 EXPECT_EQ(12u, remaining);
409
410 // Write at offset 12, this should fail.
411 EXPECT_EQ(SR_BLOCK, buf.WriteOffset(in, 10, 12, NULL));
412
413 // Write 8 bytes at offset 4, this wraps around the buffer.
414 EXPECT_EQ(SR_SUCCESS, buf.WriteOffset(in, 8, 4, NULL));
415
416 // Number of available space remains the same until we call
417 // ConsumeWriteBuffer().
418 EXPECT_TRUE(buf.GetWriteRemaining(&remaining));
419 EXPECT_EQ(12u, remaining);
420 buf.ConsumeWriteBuffer(12);
421
422 // There's 4 bytes bypassed and 4 bytes no read so skip them and verify the
423 // 8 bytes written.
424 size_t read;
425 EXPECT_EQ(SR_SUCCESS, buf.ReadOffset(out, 8, 8, &read));
426 EXPECT_EQ(8u, read);
427 EXPECT_EQ(0, memcmp(out, in, 8));
428
429 // There should still be 16 bytes available for reading.
430 EXPECT_TRUE(buf.GetBuffered(&buffered));
431 EXPECT_EQ(16u, buffered);
432
433 // Read at offset 16, this should fail since we don't have that much data.
434 EXPECT_EQ(SR_BLOCK, buf.ReadOffset(out, 10, 16, NULL));
435}
436
437TEST(AsyncWriteTest, TestWrite) {
438 FifoBuffer* buf = new FifoBuffer(100);
439 AsyncWriteStream stream(buf, Thread::Current());
440 EXPECT_EQ(SS_OPEN, stream.GetState());
441
442 // Write "abc". Will go to the logging thread, which is the current
443 // thread.
444 stream.Write("abc", 3, NULL, NULL);
445 char bytes[100];
446 size_t count;
447 // Messages on the thread's queue haven't been processed, so "abc"
448 // hasn't been written yet.
449 EXPECT_NE(SR_SUCCESS, buf->ReadOffset(&bytes, 3, 0, &count));
450 // Now we process the messages on the thread's queue, so "abc" has
451 // been written.
452 EXPECT_TRUE_WAIT(SR_SUCCESS == buf->ReadOffset(&bytes, 3, 0, &count), 10);
453 EXPECT_EQ(3u, count);
454 EXPECT_EQ(0, memcmp(bytes, "abc", 3));
455
456 // Write "def". Will go to the logging thread, which is the current
457 // thread.
458 stream.Write("d", 1, &count, NULL);
459 stream.Write("e", 1, &count, NULL);
460 stream.Write("f", 1, &count, NULL);
461 EXPECT_EQ(1u, count);
462 // Messages on the thread's queue haven't been processed, so "def"
463 // hasn't been written yet.
464 EXPECT_NE(SR_SUCCESS, buf->ReadOffset(&bytes, 3, 3, &count));
465 // Flush() causes the message to be processed, so "def" has now been
466 // written.
467 stream.Flush();
468 EXPECT_EQ(SR_SUCCESS, buf->ReadOffset(&bytes, 3, 3, &count));
469 EXPECT_EQ(3u, count);
470 EXPECT_EQ(0, memcmp(bytes, "def", 3));
471
472 // Write "xyz". Will go to the logging thread, which is the current
473 // thread.
474 stream.Write("xyz", 3, &count, NULL);
475 EXPECT_EQ(3u, count);
476 // Messages on the thread's queue haven't been processed, so "xyz"
477 // hasn't been written yet.
478 EXPECT_NE(SR_SUCCESS, buf->ReadOffset(&bytes, 3, 6, &count));
479 // Close() causes the message to be processed, so "xyz" has now been
480 // written.
481 stream.Close();
482 EXPECT_EQ(SR_SUCCESS, buf->ReadOffset(&bytes, 3, 6, &count));
483 EXPECT_EQ(3u, count);
484 EXPECT_EQ(0, memcmp(bytes, "xyz", 3));
485 EXPECT_EQ(SS_CLOSED, stream.GetState());
486
487 // Is't closed, so the writes should fail.
488 EXPECT_EQ(SR_ERROR, stream.Write("000", 3, NULL, NULL));
489
490}
491
492} // namespace rtc