blob: 116badd9157825b1adf16ffe4c0adc2e59355227 [file] [log] [blame]
Niels Möller13339482019-03-28 13:30:15 +01001/*
2 * Copyright 2019 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 "rtc_base/memory/fifo_buffer.h"
12
13#include <algorithm>
14
15#include "rtc_base/thread.h"
16
17namespace rtc {
18
19FifoBuffer::FifoBuffer(size_t size)
20 : state_(SS_OPEN),
21 buffer_(new char[size]),
22 buffer_length_(size),
23 data_length_(0),
24 read_position_(0),
25 owner_(Thread::Current()) {
26 // all events are done on the owner_ thread
27}
28
29FifoBuffer::FifoBuffer(size_t size, Thread* owner)
30 : state_(SS_OPEN),
31 buffer_(new char[size]),
32 buffer_length_(size),
33 data_length_(0),
34 read_position_(0),
35 owner_(owner) {
36 // all events are done on the owner_ thread
37}
38
39FifoBuffer::~FifoBuffer() {}
40
41bool FifoBuffer::GetBuffered(size_t* size) const {
Markus Handell18523c32020-07-08 17:55:58 +020042 webrtc::MutexLock lock(&mutex_);
Niels Möller13339482019-03-28 13:30:15 +010043 *size = data_length_;
44 return true;
45}
46
Niels Möller13339482019-03-28 13:30:15 +010047StreamState FifoBuffer::GetState() const {
Markus Handell18523c32020-07-08 17:55:58 +020048 webrtc::MutexLock lock(&mutex_);
Niels Möller13339482019-03-28 13:30:15 +010049 return state_;
50}
51
52StreamResult FifoBuffer::Read(void* buffer,
53 size_t bytes,
54 size_t* bytes_read,
55 int* error) {
Markus Handell18523c32020-07-08 17:55:58 +020056 webrtc::MutexLock lock(&mutex_);
Niels Möller13339482019-03-28 13:30:15 +010057 const bool was_writable = data_length_ < buffer_length_;
58 size_t copy = 0;
Niels Mölleracf4f552021-09-27 11:51:17 +020059 StreamResult result = ReadLocked(buffer, bytes, &copy);
Niels Möller13339482019-03-28 13:30:15 +010060
61 if (result == SR_SUCCESS) {
62 // If read was successful then adjust the read position and number of
63 // bytes buffered.
64 read_position_ = (read_position_ + copy) % buffer_length_;
65 data_length_ -= copy;
66 if (bytes_read) {
67 *bytes_read = copy;
68 }
69
70 // if we were full before, and now we're not, post an event
71 if (!was_writable && copy > 0) {
Tommi04482982020-10-05 12:43:53 +000072 PostEvent(SE_WRITE, 0);
Niels Möller13339482019-03-28 13:30:15 +010073 }
74 }
75 return result;
76}
77
78StreamResult FifoBuffer::Write(const void* buffer,
79 size_t bytes,
80 size_t* bytes_written,
81 int* error) {
Markus Handell18523c32020-07-08 17:55:58 +020082 webrtc::MutexLock lock(&mutex_);
Niels Möller13339482019-03-28 13:30:15 +010083
84 const bool was_readable = (data_length_ > 0);
85 size_t copy = 0;
Niels Mölleracf4f552021-09-27 11:51:17 +020086 StreamResult result = WriteLocked(buffer, bytes, &copy);
Niels Möller13339482019-03-28 13:30:15 +010087
88 if (result == SR_SUCCESS) {
89 // If write was successful then adjust the number of readable bytes.
90 data_length_ += copy;
91 if (bytes_written) {
92 *bytes_written = copy;
93 }
94
95 // if we didn't have any data to read before, and now we do, post an event
96 if (!was_readable && copy > 0) {
Tommi04482982020-10-05 12:43:53 +000097 PostEvent(SE_READ, 0);
Niels Möller13339482019-03-28 13:30:15 +010098 }
99 }
100 return result;
101}
102
103void FifoBuffer::Close() {
Markus Handell18523c32020-07-08 17:55:58 +0200104 webrtc::MutexLock lock(&mutex_);
Niels Möller13339482019-03-28 13:30:15 +0100105 state_ = SS_CLOSED;
106}
107
108const void* FifoBuffer::GetReadData(size_t* size) {
Markus Handell18523c32020-07-08 17:55:58 +0200109 webrtc::MutexLock lock(&mutex_);
Niels Möller13339482019-03-28 13:30:15 +0100110 *size = (read_position_ + data_length_ <= buffer_length_)
111 ? data_length_
112 : buffer_length_ - read_position_;
113 return &buffer_[read_position_];
114}
115
116void FifoBuffer::ConsumeReadData(size_t size) {
Markus Handell18523c32020-07-08 17:55:58 +0200117 webrtc::MutexLock lock(&mutex_);
Niels Möller13339482019-03-28 13:30:15 +0100118 RTC_DCHECK(size <= data_length_);
119 const bool was_writable = data_length_ < buffer_length_;
120 read_position_ = (read_position_ + size) % buffer_length_;
121 data_length_ -= size;
122 if (!was_writable && size > 0) {
Tommi04482982020-10-05 12:43:53 +0000123 PostEvent(SE_WRITE, 0);
Niels Möller13339482019-03-28 13:30:15 +0100124 }
125}
126
127void* FifoBuffer::GetWriteBuffer(size_t* size) {
Markus Handell18523c32020-07-08 17:55:58 +0200128 webrtc::MutexLock lock(&mutex_);
Niels Möller13339482019-03-28 13:30:15 +0100129 if (state_ == SS_CLOSED) {
130 return nullptr;
131 }
132
133 // if empty, reset the write position to the beginning, so we can get
134 // the biggest possible block
135 if (data_length_ == 0) {
136 read_position_ = 0;
137 }
138
139 const size_t write_position =
140 (read_position_ + data_length_) % buffer_length_;
141 *size = (write_position > read_position_ || data_length_ == 0)
142 ? buffer_length_ - write_position
143 : read_position_ - write_position;
144 return &buffer_[write_position];
145}
146
147void FifoBuffer::ConsumeWriteBuffer(size_t size) {
Markus Handell18523c32020-07-08 17:55:58 +0200148 webrtc::MutexLock lock(&mutex_);
Niels Möller13339482019-03-28 13:30:15 +0100149 RTC_DCHECK(size <= buffer_length_ - data_length_);
150 const bool was_readable = (data_length_ > 0);
151 data_length_ += size;
152 if (!was_readable && size > 0) {
Tommi04482982020-10-05 12:43:53 +0000153 PostEvent(SE_READ, 0);
Niels Möller13339482019-03-28 13:30:15 +0100154 }
155}
156
Niels Mölleracf4f552021-09-27 11:51:17 +0200157StreamResult FifoBuffer::ReadLocked(void* buffer,
158 size_t bytes,
159 size_t* bytes_read) {
160 if (data_length_ == 0) {
Niels Möller13339482019-03-28 13:30:15 +0100161 return (state_ != SS_CLOSED) ? SR_BLOCK : SR_EOS;
162 }
163
Niels Mölleracf4f552021-09-27 11:51:17 +0200164 const size_t available = data_length_;
165 const size_t read_position = read_position_ % buffer_length_;
Niels Möller13339482019-03-28 13:30:15 +0100166 const size_t copy = std::min(bytes, available);
167 const size_t tail_copy = std::min(copy, buffer_length_ - read_position);
168 char* const p = static_cast<char*>(buffer);
169 memcpy(p, &buffer_[read_position], tail_copy);
170 memcpy(p + tail_copy, &buffer_[0], copy - tail_copy);
171
172 if (bytes_read) {
173 *bytes_read = copy;
174 }
175 return SR_SUCCESS;
176}
177
Niels Mölleracf4f552021-09-27 11:51:17 +0200178StreamResult FifoBuffer::WriteLocked(const void* buffer,
179 size_t bytes,
180 size_t* bytes_written) {
Niels Möller13339482019-03-28 13:30:15 +0100181 if (state_ == SS_CLOSED) {
182 return SR_EOS;
183 }
184
Niels Mölleracf4f552021-09-27 11:51:17 +0200185 if (data_length_ >= buffer_length_) {
Niels Möller13339482019-03-28 13:30:15 +0100186 return SR_BLOCK;
187 }
188
Niels Mölleracf4f552021-09-27 11:51:17 +0200189 const size_t available = buffer_length_ - data_length_;
Niels Möller13339482019-03-28 13:30:15 +0100190 const size_t write_position =
Niels Mölleracf4f552021-09-27 11:51:17 +0200191 (read_position_ + data_length_) % buffer_length_;
Niels Möller13339482019-03-28 13:30:15 +0100192 const size_t copy = std::min(bytes, available);
193 const size_t tail_copy = std::min(copy, buffer_length_ - write_position);
194 const char* const p = static_cast<const char*>(buffer);
195 memcpy(&buffer_[write_position], p, tail_copy);
196 memcpy(&buffer_[0], p + tail_copy, copy - tail_copy);
197
198 if (bytes_written) {
199 *bytes_written = copy;
200 }
201 return SR_SUCCESS;
202}
203
204} // namespace rtc