blob: 0541bf6c01d5bccdb09924a7c587eacc2acfe73c [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>
andresp@webrtc.orgff689be2015-02-12 11:54:26 +000012#include <algorithm>
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000013#include <string>
andresp@webrtc.orgff689be2015-02-12 11:54:26 +000014
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020015#include "rtc_base/checks.h"
Yves Gerey988cc082018-10-23 12:03:01 +020016#include "rtc_base/location.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020017#include "rtc_base/messagequeue.h"
18#include "rtc_base/stream.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020019#include "rtc_base/thread.h"
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000020
21#if defined(WEBRTC_WIN)
Patrik Höglunda8005cf2017-12-13 16:05:42 +010022#include <windows.h>
Yves Gerey988cc082018-10-23 12:03:01 +020023
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000024#define fileno _fileno
Yves Gerey988cc082018-10-23 12:03:01 +020025#include "rtc_base/stringutils.h"
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000026#endif
27
28namespace rtc {
29
30///////////////////////////////////////////////////////////////////////////////
31// StreamInterface
32///////////////////////////////////////////////////////////////////////////////
Yves Gerey665174f2018-06-19 15:03:05 +020033StreamInterface::~StreamInterface() {}
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000034
Yves Gerey665174f2018-06-19 15:03:05 +020035StreamResult StreamInterface::WriteAll(const void* data,
36 size_t data_len,
37 size_t* written,
38 int* error) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000039 StreamResult result = SR_SUCCESS;
40 size_t total_written = 0, current_written;
41 while (total_written < data_len) {
42 result = Write(static_cast<const char*>(data) + total_written,
43 data_len - total_written, &current_written, error);
44 if (result != SR_SUCCESS)
45 break;
46 total_written += current_written;
47 }
48 if (written)
49 *written = total_written;
50 return result;
51}
52
Yves Gerey665174f2018-06-19 15:03:05 +020053StreamResult StreamInterface::ReadAll(void* buffer,
54 size_t buffer_len,
55 size_t* read,
56 int* error) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000057 StreamResult result = SR_SUCCESS;
58 size_t total_read = 0, current_read;
59 while (total_read < buffer_len) {
60 result = Read(static_cast<char*>(buffer) + total_read,
61 buffer_len - total_read, &current_read, error);
62 if (result != SR_SUCCESS)
63 break;
64 total_read += current_read;
65 }
66 if (read)
67 *read = total_read;
68 return result;
69}
70
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000071void StreamInterface::PostEvent(Thread* t, int events, int err) {
Taylor Brandstetter5d97a9a2016-06-10 14:17:27 -070072 t->Post(RTC_FROM_HERE, this, MSG_POST_EVENT,
73 new StreamEventData(events, err));
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000074}
75
76void StreamInterface::PostEvent(int events, int err) {
77 PostEvent(Thread::Current(), events, err);
78}
79
kwiberg@webrtc.org67186fe2015-03-09 22:21:53 +000080bool StreamInterface::SetPosition(size_t position) {
81 return false;
82}
83
84bool StreamInterface::GetPosition(size_t* position) const {
85 return false;
86}
87
kwiberg@webrtc.org67186fe2015-03-09 22:21:53 +000088bool StreamInterface::Flush() {
89 return false;
90}
91
Yves Gerey665174f2018-06-19 15:03:05 +020092StreamInterface::StreamInterface() {}
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000093
94void StreamInterface::OnMessage(Message* msg) {
95 if (MSG_POST_EVENT == msg->message_id) {
96 StreamEventData* pe = static_cast<StreamEventData*>(msg->pdata);
97 SignalEvent(this, pe->events, pe->error);
98 delete msg->pdata;
99 }
100}
101
102///////////////////////////////////////////////////////////////////////////////
103// StreamAdapterInterface
104///////////////////////////////////////////////////////////////////////////////
105
106StreamAdapterInterface::StreamAdapterInterface(StreamInterface* stream,
107 bool owned)
108 : stream_(stream), owned_(owned) {
deadbeef37f5ecf2017-02-27 14:06:41 -0800109 if (nullptr != stream_)
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000110 stream_->SignalEvent.connect(this, &StreamAdapterInterface::OnEvent);
111}
112
kwiberg@webrtc.org67186fe2015-03-09 22:21:53 +0000113StreamState StreamAdapterInterface::GetState() const {
114 return stream_->GetState();
115}
116StreamResult StreamAdapterInterface::Read(void* buffer,
117 size_t buffer_len,
118 size_t* read,
119 int* error) {
120 return stream_->Read(buffer, buffer_len, read, error);
121}
122StreamResult StreamAdapterInterface::Write(const void* data,
123 size_t data_len,
124 size_t* written,
125 int* error) {
126 return stream_->Write(data, data_len, written, error);
127}
128void StreamAdapterInterface::Close() {
129 stream_->Close();
130}
131
132bool StreamAdapterInterface::SetPosition(size_t position) {
133 return stream_->SetPosition(position);
134}
135
136bool StreamAdapterInterface::GetPosition(size_t* position) const {
137 return stream_->GetPosition(position);
138}
139
kwiberg@webrtc.org67186fe2015-03-09 22:21:53 +0000140bool StreamAdapterInterface::Flush() {
141 return stream_->Flush();
142}
143
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000144void StreamAdapterInterface::Attach(StreamInterface* stream, bool owned) {
deadbeef37f5ecf2017-02-27 14:06:41 -0800145 if (nullptr != stream_)
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000146 stream_->SignalEvent.disconnect(this);
147 if (owned_)
148 delete stream_;
149 stream_ = stream;
150 owned_ = owned;
deadbeef37f5ecf2017-02-27 14:06:41 -0800151 if (nullptr != stream_)
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000152 stream_->SignalEvent.connect(this, &StreamAdapterInterface::OnEvent);
153}
154
155StreamInterface* StreamAdapterInterface::Detach() {
deadbeef37f5ecf2017-02-27 14:06:41 -0800156 if (nullptr != stream_)
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000157 stream_->SignalEvent.disconnect(this);
158 StreamInterface* stream = stream_;
deadbeef37f5ecf2017-02-27 14:06:41 -0800159 stream_ = nullptr;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000160 return stream;
161}
162
163StreamAdapterInterface::~StreamAdapterInterface() {
164 if (owned_)
165 delete stream_;
166}
167
kwiberg@webrtc.org67186fe2015-03-09 22:21:53 +0000168void StreamAdapterInterface::OnEvent(StreamInterface* stream,
169 int events,
170 int err) {
171 SignalEvent(this, events, err);
172}
173
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000174///////////////////////////////////////////////////////////////////////////////
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000175// FileStream
176///////////////////////////////////////////////////////////////////////////////
177
deadbeef37f5ecf2017-02-27 14:06:41 -0800178FileStream::FileStream() : file_(nullptr) {}
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000179
180FileStream::~FileStream() {
181 FileStream::Close();
182}
183
Yves Gerey665174f2018-06-19 15:03:05 +0200184bool FileStream::Open(const std::string& filename,
185 const char* mode,
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000186 int* error) {
187 Close();
188#if defined(WEBRTC_WIN)
189 std::wstring wfilename;
190 if (Utf8ToWindowsFilename(filename, &wfilename)) {
191 file_ = _wfopen(wfilename.c_str(), ToUtf16(mode).c_str());
192 } else {
193 if (error) {
194 *error = -1;
195 return false;
196 }
197 }
198#else
199 file_ = fopen(filename.c_str(), mode);
200#endif
201 if (!file_ && error) {
202 *error = errno;
203 }
deadbeef37f5ecf2017-02-27 14:06:41 -0800204 return (file_ != nullptr);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000205}
206
Yves Gerey665174f2018-06-19 15:03:05 +0200207bool FileStream::OpenShare(const std::string& filename,
208 const char* mode,
209 int shflag,
210 int* error) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000211 Close();
212#if defined(WEBRTC_WIN)
213 std::wstring wfilename;
214 if (Utf8ToWindowsFilename(filename, &wfilename)) {
215 file_ = _wfsopen(wfilename.c_str(), ToUtf16(mode).c_str(), shflag);
216 if (!file_ && error) {
217 *error = errno;
218 return false;
219 }
deadbeef37f5ecf2017-02-27 14:06:41 -0800220 return file_ != nullptr;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000221 } else {
222 if (error) {
223 *error = -1;
224 }
225 return false;
226 }
227#else
228 return Open(filename, mode, error);
229#endif
230}
231
232bool FileStream::DisableBuffering() {
233 if (!file_)
234 return false;
deadbeef37f5ecf2017-02-27 14:06:41 -0800235 return (setvbuf(file_, nullptr, _IONBF, 0) == 0);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000236}
237
238StreamState FileStream::GetState() const {
deadbeef37f5ecf2017-02-27 14:06:41 -0800239 return (file_ == nullptr) ? SS_CLOSED : SS_OPEN;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000240}
241
Yves Gerey665174f2018-06-19 15:03:05 +0200242StreamResult FileStream::Read(void* buffer,
243 size_t buffer_len,
244 size_t* read,
245 int* error) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000246 if (!file_)
247 return SR_EOS;
248 size_t result = fread(buffer, 1, buffer_len, file_);
249 if ((result == 0) && (buffer_len > 0)) {
250 if (feof(file_))
251 return SR_EOS;
252 if (error)
253 *error = errno;
254 return SR_ERROR;
255 }
256 if (read)
257 *read = result;
258 return SR_SUCCESS;
259}
260
Yves Gerey665174f2018-06-19 15:03:05 +0200261StreamResult FileStream::Write(const void* data,
262 size_t data_len,
263 size_t* written,
264 int* error) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000265 if (!file_)
266 return SR_EOS;
267 size_t result = fwrite(data, 1, data_len, file_);
268 if ((result == 0) && (data_len > 0)) {
269 if (error)
270 *error = errno;
271 return SR_ERROR;
272 }
273 if (written)
274 *written = result;
275 return SR_SUCCESS;
276}
277
278void FileStream::Close() {
279 if (file_) {
280 DoClose();
deadbeef37f5ecf2017-02-27 14:06:41 -0800281 file_ = nullptr;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000282 }
283}
284
285bool FileStream::SetPosition(size_t position) {
286 if (!file_)
287 return false;
288 return (fseek(file_, static_cast<int>(position), SEEK_SET) == 0);
289}
290
291bool FileStream::GetPosition(size_t* position) const {
deadbeef37f5ecf2017-02-27 14:06:41 -0800292 RTC_DCHECK(nullptr != position);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000293 if (!file_)
294 return false;
295 long result = ftell(file_);
296 if (result < 0)
297 return false;
298 if (position)
299 *position = result;
300 return true;
301}
302
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000303bool FileStream::Flush() {
304 if (file_) {
305 return (0 == fflush(file_));
306 }
307 // try to flush empty file?
nissec80e7412017-01-11 05:56:46 -0800308 RTC_NOTREACHED();
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000309 return false;
310}
311
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000312void FileStream::DoClose() {
313 fclose(file_);
314}
315
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000316///////////////////////////////////////////////////////////////////////////////
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000317// FifoBuffer
318///////////////////////////////////////////////////////////////////////////////
319
320FifoBuffer::FifoBuffer(size_t size)
Yves Gerey665174f2018-06-19 15:03:05 +0200321 : state_(SS_OPEN),
322 buffer_(new char[size]),
323 buffer_length_(size),
324 data_length_(0),
325 read_position_(0),
326 owner_(Thread::Current()) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000327 // all events are done on the owner_ thread
328}
329
330FifoBuffer::FifoBuffer(size_t size, Thread* owner)
Yves Gerey665174f2018-06-19 15:03:05 +0200331 : state_(SS_OPEN),
332 buffer_(new char[size]),
333 buffer_length_(size),
334 data_length_(0),
335 read_position_(0),
336 owner_(owner) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000337 // all events are done on the owner_ thread
338}
339
Yves Gerey665174f2018-06-19 15:03:05 +0200340FifoBuffer::~FifoBuffer() {}
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000341
342bool FifoBuffer::GetBuffered(size_t* size) const {
343 CritScope cs(&crit_);
344 *size = data_length_;
345 return true;
346}
347
348bool FifoBuffer::SetCapacity(size_t size) {
349 CritScope cs(&crit_);
350 if (data_length_ > size) {
351 return false;
352 }
353
354 if (size != buffer_length_) {
355 char* buffer = new char[size];
356 const size_t copy = data_length_;
andresp@webrtc.orgff689be2015-02-12 11:54:26 +0000357 const size_t tail_copy = std::min(copy, buffer_length_ - read_position_);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000358 memcpy(buffer, &buffer_[read_position_], tail_copy);
359 memcpy(buffer + tail_copy, &buffer_[0], copy - tail_copy);
360 buffer_.reset(buffer);
361 read_position_ = 0;
362 buffer_length_ = size;
363 }
364 return true;
365}
366
Yves Gerey665174f2018-06-19 15:03:05 +0200367StreamResult FifoBuffer::ReadOffset(void* buffer,
368 size_t bytes,
369 size_t offset,
370 size_t* bytes_read) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000371 CritScope cs(&crit_);
372 return ReadOffsetLocked(buffer, bytes, offset, bytes_read);
373}
374
Yves Gerey665174f2018-06-19 15:03:05 +0200375StreamResult FifoBuffer::WriteOffset(const void* buffer,
376 size_t bytes,
377 size_t offset,
378 size_t* bytes_written) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000379 CritScope cs(&crit_);
380 return WriteOffsetLocked(buffer, bytes, offset, bytes_written);
381}
382
383StreamState FifoBuffer::GetState() const {
jbauch097d5492016-02-09 02:30:34 -0800384 CritScope cs(&crit_);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000385 return state_;
386}
387
Yves Gerey665174f2018-06-19 15:03:05 +0200388StreamResult FifoBuffer::Read(void* buffer,
389 size_t bytes,
390 size_t* bytes_read,
391 int* error) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000392 CritScope cs(&crit_);
393 const bool was_writable = data_length_ < buffer_length_;
394 size_t copy = 0;
395 StreamResult result = ReadOffsetLocked(buffer, bytes, 0, &copy);
396
397 if (result == SR_SUCCESS) {
398 // If read was successful then adjust the read position and number of
399 // bytes buffered.
400 read_position_ = (read_position_ + copy) % buffer_length_;
401 data_length_ -= copy;
402 if (bytes_read) {
403 *bytes_read = copy;
404 }
405
406 // if we were full before, and now we're not, post an event
407 if (!was_writable && copy > 0) {
408 PostEvent(owner_, SE_WRITE, 0);
409 }
410 }
411 return result;
412}
413
Yves Gerey665174f2018-06-19 15:03:05 +0200414StreamResult FifoBuffer::Write(const void* buffer,
415 size_t bytes,
416 size_t* bytes_written,
417 int* error) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000418 CritScope cs(&crit_);
419
420 const bool was_readable = (data_length_ > 0);
421 size_t copy = 0;
422 StreamResult result = WriteOffsetLocked(buffer, bytes, 0, &copy);
423
424 if (result == SR_SUCCESS) {
425 // If write was successful then adjust the number of readable bytes.
426 data_length_ += copy;
427 if (bytes_written) {
428 *bytes_written = copy;
429 }
430
431 // if we didn't have any data to read before, and now we do, post an event
432 if (!was_readable && copy > 0) {
433 PostEvent(owner_, SE_READ, 0);
434 }
435 }
436 return result;
437}
438
439void FifoBuffer::Close() {
440 CritScope cs(&crit_);
441 state_ = SS_CLOSED;
442}
443
444const void* FifoBuffer::GetReadData(size_t* size) {
445 CritScope cs(&crit_);
Yves Gerey665174f2018-06-19 15:03:05 +0200446 *size = (read_position_ + data_length_ <= buffer_length_)
447 ? data_length_
448 : buffer_length_ - read_position_;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000449 return &buffer_[read_position_];
450}
451
452void FifoBuffer::ConsumeReadData(size_t size) {
453 CritScope cs(&crit_);
nisseede5da42017-01-12 05:15:36 -0800454 RTC_DCHECK(size <= data_length_);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000455 const bool was_writable = data_length_ < buffer_length_;
456 read_position_ = (read_position_ + size) % buffer_length_;
457 data_length_ -= size;
458 if (!was_writable && size > 0) {
459 PostEvent(owner_, SE_WRITE, 0);
460 }
461}
462
463void* FifoBuffer::GetWriteBuffer(size_t* size) {
464 CritScope cs(&crit_);
465 if (state_ == SS_CLOSED) {
deadbeef37f5ecf2017-02-27 14:06:41 -0800466 return nullptr;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000467 }
468
469 // if empty, reset the write position to the beginning, so we can get
470 // the biggest possible block
471 if (data_length_ == 0) {
472 read_position_ = 0;
473 }
474
Yves Gerey665174f2018-06-19 15:03:05 +0200475 const size_t write_position =
476 (read_position_ + data_length_) % buffer_length_;
477 *size = (write_position > read_position_ || data_length_ == 0)
478 ? buffer_length_ - write_position
479 : read_position_ - write_position;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000480 return &buffer_[write_position];
481}
482
483void FifoBuffer::ConsumeWriteBuffer(size_t size) {
484 CritScope cs(&crit_);
nisseede5da42017-01-12 05:15:36 -0800485 RTC_DCHECK(size <= buffer_length_ - data_length_);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000486 const bool was_readable = (data_length_ > 0);
487 data_length_ += size;
488 if (!was_readable && size > 0) {
489 PostEvent(owner_, SE_READ, 0);
490 }
491}
492
493bool FifoBuffer::GetWriteRemaining(size_t* size) const {
494 CritScope cs(&crit_);
495 *size = buffer_length_ - data_length_;
496 return true;
497}
498
499StreamResult FifoBuffer::ReadOffsetLocked(void* buffer,
500 size_t bytes,
501 size_t offset,
502 size_t* bytes_read) {
503 if (offset >= data_length_) {
504 return (state_ != SS_CLOSED) ? SR_BLOCK : SR_EOS;
505 }
506
507 const size_t available = data_length_ - offset;
508 const size_t read_position = (read_position_ + offset) % buffer_length_;
andresp@webrtc.orgff689be2015-02-12 11:54:26 +0000509 const size_t copy = std::min(bytes, available);
510 const size_t tail_copy = std::min(copy, buffer_length_ - read_position);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000511 char* const p = static_cast<char*>(buffer);
512 memcpy(p, &buffer_[read_position], tail_copy);
513 memcpy(p + tail_copy, &buffer_[0], copy - tail_copy);
514
515 if (bytes_read) {
516 *bytes_read = copy;
517 }
518 return SR_SUCCESS;
519}
520
521StreamResult FifoBuffer::WriteOffsetLocked(const void* buffer,
522 size_t bytes,
523 size_t offset,
524 size_t* bytes_written) {
525 if (state_ == SS_CLOSED) {
526 return SR_EOS;
527 }
528
529 if (data_length_ + offset >= buffer_length_) {
530 return SR_BLOCK;
531 }
532
533 const size_t available = buffer_length_ - data_length_ - offset;
Yves Gerey665174f2018-06-19 15:03:05 +0200534 const size_t write_position =
535 (read_position_ + data_length_ + offset) % buffer_length_;
andresp@webrtc.orgff689be2015-02-12 11:54:26 +0000536 const size_t copy = std::min(bytes, available);
537 const size_t tail_copy = std::min(copy, buffer_length_ - write_position);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000538 const char* const p = static_cast<const char*>(buffer);
539 memcpy(&buffer_[write_position], p, tail_copy);
540 memcpy(&buffer_[0], p + tail_copy, copy - tail_copy);
541
542 if (bytes_written) {
543 *bytes_written = copy;
544 }
545 return SR_SUCCESS;
546}
547
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000548} // namespace rtc