blob: abaa96ee51774b76c38ecb1e7e31172ed649f862 [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 */
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000010#include <errno.h>
Yves Gerey988cc082018-10-23 12:03:01 +020011#include <string.h>
Yves Gerey665174f2018-06-19 15:03:05 +020012#include <sys/stat.h>
andresp@webrtc.orgff689be2015-02-12 11:54:26 +000013#include <algorithm>
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000014#include <string>
andresp@webrtc.orgff689be2015-02-12 11:54:26 +000015
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020016#include "rtc_base/checks.h"
Yves Gerey988cc082018-10-23 12:03:01 +020017#include "rtc_base/location.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020018#include "rtc_base/messagequeue.h"
19#include "rtc_base/stream.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020020#include "rtc_base/thread.h"
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000021
22#if defined(WEBRTC_WIN)
Patrik Höglunda8005cf2017-12-13 16:05:42 +010023#include <windows.h>
Yves Gerey988cc082018-10-23 12:03:01 +020024
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000025#define fileno _fileno
Yves Gerey988cc082018-10-23 12:03:01 +020026#include "rtc_base/stringutils.h"
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000027#endif
28
29namespace rtc {
30
31///////////////////////////////////////////////////////////////////////////////
32// StreamInterface
33///////////////////////////////////////////////////////////////////////////////
Yves Gerey665174f2018-06-19 15:03:05 +020034StreamInterface::~StreamInterface() {}
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000035
Yves Gerey665174f2018-06-19 15:03:05 +020036StreamResult StreamInterface::WriteAll(const void* data,
37 size_t data_len,
38 size_t* written,
39 int* error) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000040 StreamResult result = SR_SUCCESS;
41 size_t total_written = 0, current_written;
42 while (total_written < data_len) {
43 result = Write(static_cast<const char*>(data) + total_written,
44 data_len - total_written, &current_written, error);
45 if (result != SR_SUCCESS)
46 break;
47 total_written += current_written;
48 }
49 if (written)
50 *written = total_written;
51 return result;
52}
53
Yves Gerey665174f2018-06-19 15:03:05 +020054StreamResult StreamInterface::ReadAll(void* buffer,
55 size_t buffer_len,
56 size_t* read,
57 int* error) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000058 StreamResult result = SR_SUCCESS;
59 size_t total_read = 0, current_read;
60 while (total_read < buffer_len) {
61 result = Read(static_cast<char*>(buffer) + total_read,
62 buffer_len - total_read, &current_read, error);
63 if (result != SR_SUCCESS)
64 break;
65 total_read += current_read;
66 }
67 if (read)
68 *read = total_read;
69 return result;
70}
71
72StreamResult StreamInterface::ReadLine(std::string* line) {
73 line->clear();
74 StreamResult result = SR_SUCCESS;
75 while (true) {
76 char ch;
deadbeef37f5ecf2017-02-27 14:06:41 -080077 result = Read(&ch, sizeof(ch), nullptr, nullptr);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000078 if (result != SR_SUCCESS) {
79 break;
80 }
81 if (ch == '\n') {
82 break;
83 }
84 line->push_back(ch);
85 }
86 if (!line->empty()) { // give back the line we've collected so far with
87 result = SR_SUCCESS; // a success code. Otherwise return the last code
88 }
89 return result;
90}
91
92void StreamInterface::PostEvent(Thread* t, int events, int err) {
Taylor Brandstetter5d97a9a2016-06-10 14:17:27 -070093 t->Post(RTC_FROM_HERE, this, MSG_POST_EVENT,
94 new StreamEventData(events, err));
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000095}
96
97void StreamInterface::PostEvent(int events, int err) {
98 PostEvent(Thread::Current(), events, err);
99}
100
kwiberg@webrtc.org67186fe2015-03-09 22:21:53 +0000101const void* StreamInterface::GetReadData(size_t* data_len) {
deadbeef37f5ecf2017-02-27 14:06:41 -0800102 return nullptr;
kwiberg@webrtc.org67186fe2015-03-09 22:21:53 +0000103}
104
105void* StreamInterface::GetWriteBuffer(size_t* buf_len) {
deadbeef37f5ecf2017-02-27 14:06:41 -0800106 return nullptr;
kwiberg@webrtc.org67186fe2015-03-09 22:21:53 +0000107}
108
109bool StreamInterface::SetPosition(size_t position) {
110 return false;
111}
112
113bool StreamInterface::GetPosition(size_t* position) const {
114 return false;
115}
116
117bool StreamInterface::GetSize(size_t* size) const {
118 return false;
119}
120
kwiberg@webrtc.org67186fe2015-03-09 22:21:53 +0000121bool StreamInterface::GetWriteRemaining(size_t* size) const {
122 return false;
123}
124
125bool StreamInterface::Flush() {
126 return false;
127}
128
129bool StreamInterface::ReserveSize(size_t size) {
130 return true;
131}
132
Yves Gerey665174f2018-06-19 15:03:05 +0200133StreamInterface::StreamInterface() {}
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000134
135void StreamInterface::OnMessage(Message* msg) {
136 if (MSG_POST_EVENT == msg->message_id) {
137 StreamEventData* pe = static_cast<StreamEventData*>(msg->pdata);
138 SignalEvent(this, pe->events, pe->error);
139 delete msg->pdata;
140 }
141}
142
143///////////////////////////////////////////////////////////////////////////////
144// StreamAdapterInterface
145///////////////////////////////////////////////////////////////////////////////
146
147StreamAdapterInterface::StreamAdapterInterface(StreamInterface* stream,
148 bool owned)
149 : stream_(stream), owned_(owned) {
deadbeef37f5ecf2017-02-27 14:06:41 -0800150 if (nullptr != stream_)
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000151 stream_->SignalEvent.connect(this, &StreamAdapterInterface::OnEvent);
152}
153
kwiberg@webrtc.org67186fe2015-03-09 22:21:53 +0000154StreamState StreamAdapterInterface::GetState() const {
155 return stream_->GetState();
156}
157StreamResult StreamAdapterInterface::Read(void* buffer,
158 size_t buffer_len,
159 size_t* read,
160 int* error) {
161 return stream_->Read(buffer, buffer_len, read, error);
162}
163StreamResult StreamAdapterInterface::Write(const void* data,
164 size_t data_len,
165 size_t* written,
166 int* error) {
167 return stream_->Write(data, data_len, written, error);
168}
169void StreamAdapterInterface::Close() {
170 stream_->Close();
171}
172
173bool StreamAdapterInterface::SetPosition(size_t position) {
174 return stream_->SetPosition(position);
175}
176
177bool StreamAdapterInterface::GetPosition(size_t* position) const {
178 return stream_->GetPosition(position);
179}
180
181bool StreamAdapterInterface::GetSize(size_t* size) const {
182 return stream_->GetSize(size);
183}
184
kwiberg@webrtc.org67186fe2015-03-09 22:21:53 +0000185bool StreamAdapterInterface::GetWriteRemaining(size_t* size) const {
186 return stream_->GetWriteRemaining(size);
187}
188
189bool StreamAdapterInterface::ReserveSize(size_t size) {
190 return stream_->ReserveSize(size);
191}
192
193bool StreamAdapterInterface::Flush() {
194 return stream_->Flush();
195}
196
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000197void StreamAdapterInterface::Attach(StreamInterface* stream, bool owned) {
deadbeef37f5ecf2017-02-27 14:06:41 -0800198 if (nullptr != stream_)
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000199 stream_->SignalEvent.disconnect(this);
200 if (owned_)
201 delete stream_;
202 stream_ = stream;
203 owned_ = owned;
deadbeef37f5ecf2017-02-27 14:06:41 -0800204 if (nullptr != stream_)
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000205 stream_->SignalEvent.connect(this, &StreamAdapterInterface::OnEvent);
206}
207
208StreamInterface* StreamAdapterInterface::Detach() {
deadbeef37f5ecf2017-02-27 14:06:41 -0800209 if (nullptr != stream_)
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000210 stream_->SignalEvent.disconnect(this);
211 StreamInterface* stream = stream_;
deadbeef37f5ecf2017-02-27 14:06:41 -0800212 stream_ = nullptr;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000213 return stream;
214}
215
216StreamAdapterInterface::~StreamAdapterInterface() {
217 if (owned_)
218 delete stream_;
219}
220
kwiberg@webrtc.org67186fe2015-03-09 22:21:53 +0000221void StreamAdapterInterface::OnEvent(StreamInterface* stream,
222 int events,
223 int err) {
224 SignalEvent(this, events, err);
225}
226
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000227///////////////////////////////////////////////////////////////////////////////
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000228// FileStream
229///////////////////////////////////////////////////////////////////////////////
230
deadbeef37f5ecf2017-02-27 14:06:41 -0800231FileStream::FileStream() : file_(nullptr) {}
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000232
233FileStream::~FileStream() {
234 FileStream::Close();
235}
236
Yves Gerey665174f2018-06-19 15:03:05 +0200237bool FileStream::Open(const std::string& filename,
238 const char* mode,
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000239 int* error) {
240 Close();
241#if defined(WEBRTC_WIN)
242 std::wstring wfilename;
243 if (Utf8ToWindowsFilename(filename, &wfilename)) {
244 file_ = _wfopen(wfilename.c_str(), ToUtf16(mode).c_str());
245 } else {
246 if (error) {
247 *error = -1;
248 return false;
249 }
250 }
251#else
252 file_ = fopen(filename.c_str(), mode);
253#endif
254 if (!file_ && error) {
255 *error = errno;
256 }
deadbeef37f5ecf2017-02-27 14:06:41 -0800257 return (file_ != nullptr);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000258}
259
Yves Gerey665174f2018-06-19 15:03:05 +0200260bool FileStream::OpenShare(const std::string& filename,
261 const char* mode,
262 int shflag,
263 int* error) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000264 Close();
265#if defined(WEBRTC_WIN)
266 std::wstring wfilename;
267 if (Utf8ToWindowsFilename(filename, &wfilename)) {
268 file_ = _wfsopen(wfilename.c_str(), ToUtf16(mode).c_str(), shflag);
269 if (!file_ && error) {
270 *error = errno;
271 return false;
272 }
deadbeef37f5ecf2017-02-27 14:06:41 -0800273 return file_ != nullptr;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000274 } else {
275 if (error) {
276 *error = -1;
277 }
278 return false;
279 }
280#else
281 return Open(filename, mode, error);
282#endif
283}
284
285bool FileStream::DisableBuffering() {
286 if (!file_)
287 return false;
deadbeef37f5ecf2017-02-27 14:06:41 -0800288 return (setvbuf(file_, nullptr, _IONBF, 0) == 0);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000289}
290
291StreamState FileStream::GetState() const {
deadbeef37f5ecf2017-02-27 14:06:41 -0800292 return (file_ == nullptr) ? SS_CLOSED : SS_OPEN;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000293}
294
Yves Gerey665174f2018-06-19 15:03:05 +0200295StreamResult FileStream::Read(void* buffer,
296 size_t buffer_len,
297 size_t* read,
298 int* error) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000299 if (!file_)
300 return SR_EOS;
301 size_t result = fread(buffer, 1, buffer_len, file_);
302 if ((result == 0) && (buffer_len > 0)) {
303 if (feof(file_))
304 return SR_EOS;
305 if (error)
306 *error = errno;
307 return SR_ERROR;
308 }
309 if (read)
310 *read = result;
311 return SR_SUCCESS;
312}
313
Yves Gerey665174f2018-06-19 15:03:05 +0200314StreamResult FileStream::Write(const void* data,
315 size_t data_len,
316 size_t* written,
317 int* error) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000318 if (!file_)
319 return SR_EOS;
320 size_t result = fwrite(data, 1, data_len, file_);
321 if ((result == 0) && (data_len > 0)) {
322 if (error)
323 *error = errno;
324 return SR_ERROR;
325 }
326 if (written)
327 *written = result;
328 return SR_SUCCESS;
329}
330
331void FileStream::Close() {
332 if (file_) {
333 DoClose();
deadbeef37f5ecf2017-02-27 14:06:41 -0800334 file_ = nullptr;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000335 }
336}
337
338bool FileStream::SetPosition(size_t position) {
339 if (!file_)
340 return false;
341 return (fseek(file_, static_cast<int>(position), SEEK_SET) == 0);
342}
343
344bool FileStream::GetPosition(size_t* position) const {
deadbeef37f5ecf2017-02-27 14:06:41 -0800345 RTC_DCHECK(nullptr != position);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000346 if (!file_)
347 return false;
348 long result = ftell(file_);
349 if (result < 0)
350 return false;
351 if (position)
352 *position = result;
353 return true;
354}
355
356bool FileStream::GetSize(size_t* size) const {
deadbeef37f5ecf2017-02-27 14:06:41 -0800357 RTC_DCHECK(nullptr != size);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000358 if (!file_)
359 return false;
360 struct stat file_stats;
361 if (fstat(fileno(file_), &file_stats) != 0)
362 return false;
363 if (size)
364 *size = file_stats.st_size;
365 return true;
366}
367
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000368bool FileStream::ReserveSize(size_t size) {
369 // TODO: extend the file to the proper length
370 return true;
371}
372
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000373bool FileStream::Flush() {
374 if (file_) {
375 return (0 == fflush(file_));
376 }
377 // try to flush empty file?
nissec80e7412017-01-11 05:56:46 -0800378 RTC_NOTREACHED();
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000379 return false;
380}
381
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000382void FileStream::DoClose() {
383 fclose(file_);
384}
385
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000386///////////////////////////////////////////////////////////////////////////////
387// MemoryStream
388///////////////////////////////////////////////////////////////////////////////
389
390MemoryStreamBase::MemoryStreamBase()
deadbeef37f5ecf2017-02-27 14:06:41 -0800391 : buffer_(nullptr), buffer_length_(0), data_length_(0), seek_position_(0) {}
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000392
393StreamState MemoryStreamBase::GetState() const {
394 return SS_OPEN;
395}
396
Yves Gerey665174f2018-06-19 15:03:05 +0200397StreamResult MemoryStreamBase::Read(void* buffer,
398 size_t bytes,
399 size_t* bytes_read,
400 int* error) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000401 if (seek_position_ >= data_length_) {
402 return SR_EOS;
403 }
404 size_t available = data_length_ - seek_position_;
405 if (bytes > available) {
406 // Read partial buffer
407 bytes = available;
408 }
409 memcpy(buffer, &buffer_[seek_position_], bytes);
410 seek_position_ += bytes;
411 if (bytes_read) {
412 *bytes_read = bytes;
413 }
414 return SR_SUCCESS;
415}
416
Yves Gerey665174f2018-06-19 15:03:05 +0200417StreamResult MemoryStreamBase::Write(const void* buffer,
418 size_t bytes,
419 size_t* bytes_written,
420 int* error) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000421 size_t available = buffer_length_ - seek_position_;
422 if (0 == available) {
423 // Increase buffer size to the larger of:
424 // a) new position rounded up to next 256 bytes
425 // b) double the previous length
andresp@webrtc.orgff689be2015-02-12 11:54:26 +0000426 size_t new_buffer_length =
427 std::max(((seek_position_ + bytes) | 0xFF) + 1, buffer_length_ * 2);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000428 StreamResult result = DoReserve(new_buffer_length, error);
429 if (SR_SUCCESS != result) {
430 return result;
431 }
nisseede5da42017-01-12 05:15:36 -0800432 RTC_DCHECK(buffer_length_ >= new_buffer_length);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000433 available = buffer_length_ - seek_position_;
434 }
435
436 if (bytes > available) {
437 bytes = available;
438 }
439 memcpy(&buffer_[seek_position_], buffer, bytes);
440 seek_position_ += bytes;
441 if (data_length_ < seek_position_) {
442 data_length_ = seek_position_;
443 }
444 if (bytes_written) {
445 *bytes_written = bytes;
446 }
447 return SR_SUCCESS;
448}
449
450void MemoryStreamBase::Close() {
451 // nothing to do
452}
453
454bool MemoryStreamBase::SetPosition(size_t position) {
455 if (position > data_length_)
456 return false;
457 seek_position_ = position;
458 return true;
459}
460
461bool MemoryStreamBase::GetPosition(size_t* position) const {
462 if (position)
463 *position = seek_position_;
464 return true;
465}
466
467bool MemoryStreamBase::GetSize(size_t* size) const {
468 if (size)
469 *size = data_length_;
470 return true;
471}
472
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000473bool MemoryStreamBase::ReserveSize(size_t size) {
deadbeef37f5ecf2017-02-27 14:06:41 -0800474 return (SR_SUCCESS == DoReserve(size, nullptr));
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000475}
476
477StreamResult MemoryStreamBase::DoReserve(size_t size, int* error) {
478 return (buffer_length_ >= size) ? SR_SUCCESS : SR_EOS;
479}
480
481///////////////////////////////////////////////////////////////////////////////
482
Niels Möller7502a9e2018-05-21 16:11:34 +0200483MemoryStream::MemoryStream() {}
484
485MemoryStream::MemoryStream(const char* data) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000486 SetData(data, strlen(data));
487}
488
Niels Möller7502a9e2018-05-21 16:11:34 +0200489MemoryStream::MemoryStream(const void* data, size_t length) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000490 SetData(data, length);
491}
492
493MemoryStream::~MemoryStream() {
Yves Gerey665174f2018-06-19 15:03:05 +0200494 delete[] buffer_;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000495}
496
497void MemoryStream::SetData(const void* data, size_t length) {
498 data_length_ = buffer_length_ = length;
Yves Gerey665174f2018-06-19 15:03:05 +0200499 delete[] buffer_;
Niels Möller7502a9e2018-05-21 16:11:34 +0200500 buffer_ = new char[buffer_length_];
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000501 memcpy(buffer_, data, data_length_);
502 seek_position_ = 0;
503}
504
505StreamResult MemoryStream::DoReserve(size_t size, int* error) {
506 if (buffer_length_ >= size)
507 return SR_SUCCESS;
508
Niels Möller7502a9e2018-05-21 16:11:34 +0200509 if (char* new_buffer = new char[size]) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000510 memcpy(new_buffer, buffer_, data_length_);
Yves Gerey665174f2018-06-19 15:03:05 +0200511 delete[] buffer_;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000512 buffer_ = new_buffer;
513 buffer_length_ = size;
514 return SR_SUCCESS;
515 }
516
517 if (error) {
518 *error = ENOMEM;
519 }
520 return SR_ERROR;
521}
522
523///////////////////////////////////////////////////////////////////////////////
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000524// FifoBuffer
525///////////////////////////////////////////////////////////////////////////////
526
527FifoBuffer::FifoBuffer(size_t size)
Yves Gerey665174f2018-06-19 15:03:05 +0200528 : state_(SS_OPEN),
529 buffer_(new char[size]),
530 buffer_length_(size),
531 data_length_(0),
532 read_position_(0),
533 owner_(Thread::Current()) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000534 // all events are done on the owner_ thread
535}
536
537FifoBuffer::FifoBuffer(size_t size, Thread* owner)
Yves Gerey665174f2018-06-19 15:03:05 +0200538 : state_(SS_OPEN),
539 buffer_(new char[size]),
540 buffer_length_(size),
541 data_length_(0),
542 read_position_(0),
543 owner_(owner) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000544 // all events are done on the owner_ thread
545}
546
Yves Gerey665174f2018-06-19 15:03:05 +0200547FifoBuffer::~FifoBuffer() {}
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000548
549bool FifoBuffer::GetBuffered(size_t* size) const {
550 CritScope cs(&crit_);
551 *size = data_length_;
552 return true;
553}
554
555bool FifoBuffer::SetCapacity(size_t size) {
556 CritScope cs(&crit_);
557 if (data_length_ > size) {
558 return false;
559 }
560
561 if (size != buffer_length_) {
562 char* buffer = new char[size];
563 const size_t copy = data_length_;
andresp@webrtc.orgff689be2015-02-12 11:54:26 +0000564 const size_t tail_copy = std::min(copy, buffer_length_ - read_position_);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000565 memcpy(buffer, &buffer_[read_position_], tail_copy);
566 memcpy(buffer + tail_copy, &buffer_[0], copy - tail_copy);
567 buffer_.reset(buffer);
568 read_position_ = 0;
569 buffer_length_ = size;
570 }
571 return true;
572}
573
Yves Gerey665174f2018-06-19 15:03:05 +0200574StreamResult FifoBuffer::ReadOffset(void* buffer,
575 size_t bytes,
576 size_t offset,
577 size_t* bytes_read) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000578 CritScope cs(&crit_);
579 return ReadOffsetLocked(buffer, bytes, offset, bytes_read);
580}
581
Yves Gerey665174f2018-06-19 15:03:05 +0200582StreamResult FifoBuffer::WriteOffset(const void* buffer,
583 size_t bytes,
584 size_t offset,
585 size_t* bytes_written) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000586 CritScope cs(&crit_);
587 return WriteOffsetLocked(buffer, bytes, offset, bytes_written);
588}
589
590StreamState FifoBuffer::GetState() const {
jbauch097d5492016-02-09 02:30:34 -0800591 CritScope cs(&crit_);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000592 return state_;
593}
594
Yves Gerey665174f2018-06-19 15:03:05 +0200595StreamResult FifoBuffer::Read(void* buffer,
596 size_t bytes,
597 size_t* bytes_read,
598 int* error) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000599 CritScope cs(&crit_);
600 const bool was_writable = data_length_ < buffer_length_;
601 size_t copy = 0;
602 StreamResult result = ReadOffsetLocked(buffer, bytes, 0, &copy);
603
604 if (result == SR_SUCCESS) {
605 // If read was successful then adjust the read position and number of
606 // bytes buffered.
607 read_position_ = (read_position_ + copy) % buffer_length_;
608 data_length_ -= copy;
609 if (bytes_read) {
610 *bytes_read = copy;
611 }
612
613 // if we were full before, and now we're not, post an event
614 if (!was_writable && copy > 0) {
615 PostEvent(owner_, SE_WRITE, 0);
616 }
617 }
618 return result;
619}
620
Yves Gerey665174f2018-06-19 15:03:05 +0200621StreamResult FifoBuffer::Write(const void* buffer,
622 size_t bytes,
623 size_t* bytes_written,
624 int* error) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000625 CritScope cs(&crit_);
626
627 const bool was_readable = (data_length_ > 0);
628 size_t copy = 0;
629 StreamResult result = WriteOffsetLocked(buffer, bytes, 0, &copy);
630
631 if (result == SR_SUCCESS) {
632 // If write was successful then adjust the number of readable bytes.
633 data_length_ += copy;
634 if (bytes_written) {
635 *bytes_written = copy;
636 }
637
638 // if we didn't have any data to read before, and now we do, post an event
639 if (!was_readable && copy > 0) {
640 PostEvent(owner_, SE_READ, 0);
641 }
642 }
643 return result;
644}
645
646void FifoBuffer::Close() {
647 CritScope cs(&crit_);
648 state_ = SS_CLOSED;
649}
650
651const void* FifoBuffer::GetReadData(size_t* size) {
652 CritScope cs(&crit_);
Yves Gerey665174f2018-06-19 15:03:05 +0200653 *size = (read_position_ + data_length_ <= buffer_length_)
654 ? data_length_
655 : buffer_length_ - read_position_;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000656 return &buffer_[read_position_];
657}
658
659void FifoBuffer::ConsumeReadData(size_t size) {
660 CritScope cs(&crit_);
nisseede5da42017-01-12 05:15:36 -0800661 RTC_DCHECK(size <= data_length_);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000662 const bool was_writable = data_length_ < buffer_length_;
663 read_position_ = (read_position_ + size) % buffer_length_;
664 data_length_ -= size;
665 if (!was_writable && size > 0) {
666 PostEvent(owner_, SE_WRITE, 0);
667 }
668}
669
670void* FifoBuffer::GetWriteBuffer(size_t* size) {
671 CritScope cs(&crit_);
672 if (state_ == SS_CLOSED) {
deadbeef37f5ecf2017-02-27 14:06:41 -0800673 return nullptr;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000674 }
675
676 // if empty, reset the write position to the beginning, so we can get
677 // the biggest possible block
678 if (data_length_ == 0) {
679 read_position_ = 0;
680 }
681
Yves Gerey665174f2018-06-19 15:03:05 +0200682 const size_t write_position =
683 (read_position_ + data_length_) % buffer_length_;
684 *size = (write_position > read_position_ || data_length_ == 0)
685 ? buffer_length_ - write_position
686 : read_position_ - write_position;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000687 return &buffer_[write_position];
688}
689
690void FifoBuffer::ConsumeWriteBuffer(size_t size) {
691 CritScope cs(&crit_);
nisseede5da42017-01-12 05:15:36 -0800692 RTC_DCHECK(size <= buffer_length_ - data_length_);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000693 const bool was_readable = (data_length_ > 0);
694 data_length_ += size;
695 if (!was_readable && size > 0) {
696 PostEvent(owner_, SE_READ, 0);
697 }
698}
699
700bool FifoBuffer::GetWriteRemaining(size_t* size) const {
701 CritScope cs(&crit_);
702 *size = buffer_length_ - data_length_;
703 return true;
704}
705
706StreamResult FifoBuffer::ReadOffsetLocked(void* buffer,
707 size_t bytes,
708 size_t offset,
709 size_t* bytes_read) {
710 if (offset >= data_length_) {
711 return (state_ != SS_CLOSED) ? SR_BLOCK : SR_EOS;
712 }
713
714 const size_t available = data_length_ - offset;
715 const size_t read_position = (read_position_ + offset) % buffer_length_;
andresp@webrtc.orgff689be2015-02-12 11:54:26 +0000716 const size_t copy = std::min(bytes, available);
717 const size_t tail_copy = std::min(copy, buffer_length_ - read_position);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000718 char* const p = static_cast<char*>(buffer);
719 memcpy(p, &buffer_[read_position], tail_copy);
720 memcpy(p + tail_copy, &buffer_[0], copy - tail_copy);
721
722 if (bytes_read) {
723 *bytes_read = copy;
724 }
725 return SR_SUCCESS;
726}
727
728StreamResult FifoBuffer::WriteOffsetLocked(const void* buffer,
729 size_t bytes,
730 size_t offset,
731 size_t* bytes_written) {
732 if (state_ == SS_CLOSED) {
733 return SR_EOS;
734 }
735
736 if (data_length_ + offset >= buffer_length_) {
737 return SR_BLOCK;
738 }
739
740 const size_t available = buffer_length_ - data_length_ - offset;
Yves Gerey665174f2018-06-19 15:03:05 +0200741 const size_t write_position =
742 (read_position_ + data_length_ + offset) % buffer_length_;
andresp@webrtc.orgff689be2015-02-12 11:54:26 +0000743 const size_t copy = std::min(bytes, available);
744 const size_t tail_copy = std::min(copy, buffer_length_ - write_position);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000745 const char* const p = static_cast<const char*>(buffer);
746 memcpy(&buffer_[write_position], p, tail_copy);
747 memcpy(&buffer_[0], p + tail_copy, copy - tail_copy);
748
749 if (bytes_written) {
750 *bytes_written = copy;
751 }
752 return SR_SUCCESS;
753}
754
deadbeeff137e972017-03-23 15:45:49 -0700755
756///////////////////////////////////////////////////////////////////////////////
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000757
758StreamResult Flow(StreamInterface* source,
deadbeef37f5ecf2017-02-27 14:06:41 -0800759 char* buffer,
760 size_t buffer_len,
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000761 StreamInterface* sink,
deadbeef37f5ecf2017-02-27 14:06:41 -0800762 size_t* data_len /* = nullptr */) {
nisseede5da42017-01-12 05:15:36 -0800763 RTC_DCHECK(buffer_len > 0);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000764
765 StreamResult result;
766 size_t count, read_pos, write_pos;
767 if (data_len) {
768 read_pos = *data_len;
769 } else {
770 read_pos = 0;
771 }
772
773 bool end_of_stream = false;
774 do {
775 // Read until buffer is full, end of stream, or error
776 while (!end_of_stream && (read_pos < buffer_len)) {
deadbeef37f5ecf2017-02-27 14:06:41 -0800777 result = source->Read(buffer + read_pos, buffer_len - read_pos, &count,
778 nullptr);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000779 if (result == SR_EOS) {
780 end_of_stream = true;
781 } else if (result != SR_SUCCESS) {
782 if (data_len) {
783 *data_len = read_pos;
784 }
785 return result;
786 } else {
787 read_pos += count;
788 }
789 }
790
791 // Write until buffer is empty, or error (including end of stream)
792 write_pos = 0;
793 while (write_pos < read_pos) {
deadbeef37f5ecf2017-02-27 14:06:41 -0800794 result = sink->Write(buffer + write_pos, read_pos - write_pos, &count,
795 nullptr);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000796 if (result != SR_SUCCESS) {
797 if (data_len) {
798 *data_len = read_pos - write_pos;
799 if (write_pos > 0) {
800 memmove(buffer, buffer + write_pos, *data_len);
801 }
802 }
803 return result;
804 }
805 write_pos += count;
806 }
807
808 read_pos = 0;
809 } while (!end_of_stream);
810
811 if (data_len) {
812 *data_len = 0;
813 }
814 return SR_SUCCESS;
815}
816
817///////////////////////////////////////////////////////////////////////////////
818
819} // namespace rtc