1 /*
2  * Copyright 2023, The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #pragma once
18 
19 #include <algorithm>
20 #include <cstdint>
21 #include <memory>
22 #include <vector>
23 
24 namespace android::audio_utils {
25 
26 /**
27  * Simple circular buffer that provides facilities to read and write single or multiple bytes
28  * to and from the buffer. This implementation is not thread-safe and the reader and
29  * writer must be on the same thread.
30  */
31 class CircularBuffer {
32  public:
33     /**
34      * \brief Create new instance specifying its maximum capacity.
35      * \param maxBytes Maximum buffer capacity, in bytes.
36      */
CircularBuffer(size_t maxBytes)37     explicit CircularBuffer(size_t maxBytes) {
38         mBuffer.resize(maxBytes);
39     }
40 
41     /**
42      * \brief Read bytes into buffer from this instance.
43      * \param buffer The buffer to read into.
44      * \param numBytes The number of bytes to read.
45      * \return The number of bytes read.
46      */
read(uint8_t * buffer,size_t numBytes)47     size_t read(uint8_t *buffer, size_t numBytes) {
48         if (empty() || numBytes == 0) {
49             return 0;
50         }
51         const auto bytesToRead = std::min(numBytes, availableToRead());
52         if (mHeadPosition > mTailPosition) {
53             memcpy(buffer, &mBuffer[mTailPosition], bytesToRead);
54             mTailPosition += bytesToRead;
55         } else {
56             // handle loop around
57             auto bytesToEnd = mBuffer.size() - mTailPosition;
58             if (bytesToRead <= bytesToEnd) {
59                 memcpy(buffer, &mBuffer[mTailPosition], bytesToRead);
60                 mTailPosition += bytesToRead;
61                 if (mTailPosition == mBuffer.size()) {
62                     mTailPosition = 0;
63                 }
64             } else {
65                 memcpy(buffer, &mBuffer[mTailPosition], bytesToEnd);
66                 const auto remaining = bytesToRead - bytesToEnd;
67                 memcpy(buffer + bytesToEnd, &mBuffer[0], remaining);
68                 mTailPosition = remaining;
69             }
70         }
71         mFull = false;
72         return bytesToRead;
73     }
74 
75     /**
76      * \brief Read out the next byte from this instance.
77      * Check that empty() is false before calling this function.
78      * \return The value of the byte read.
79      */
readByte()80     uint8_t readByte() {
81         if (empty()) {
82             return 0;
83         }
84         mFull = false;
85         auto result = mBuffer[mTailPosition++];
86         if (mTailPosition == mBuffer.size()) {
87             mTailPosition = 0;
88         }
89         return result;
90     }
91 
92     /**
93      * \brief Write bytes from buffer into this instance.
94      * \param buffer The buffer to read from.
95      * \param numBytes The number of bytes to write.
96      * \return The number of bytes written.
97      */
write(const uint8_t * buffer,size_t numBytes)98     size_t write(const uint8_t *buffer, size_t numBytes) {
99         if (mFull || numBytes == 0) {
100             return 0;
101         }
102         const auto bytesToWrite = std::min(numBytes, availableToWrite());
103         if (mHeadPosition < mTailPosition) {
104             memcpy(&mBuffer[mHeadPosition], buffer, bytesToWrite);
105             mHeadPosition += bytesToWrite;
106         } else {
107             // handle loop around
108             const auto bytesToEnd = mBuffer.size() - mHeadPosition;
109             if (bytesToWrite <= bytesToEnd) {
110                 memcpy(&mBuffer[mHeadPosition], buffer, bytesToWrite);
111                 mHeadPosition += bytesToWrite;
112                 if (mHeadPosition == mBuffer.size()) {
113                     mHeadPosition = 0;
114                 }
115             } else {
116                 memcpy(&mBuffer[mHeadPosition], buffer, bytesToEnd);
117                 const auto remaining = bytesToWrite - bytesToEnd;
118                 memcpy(&mBuffer[0], buffer + bytesToEnd, remaining);
119                 mHeadPosition = remaining;
120             }
121         }
122         mFull = (mHeadPosition == mTailPosition);
123         return bytesToWrite;
124     }
125 
126     /**
127      * \brief Write a single byte into this instance.
128      * Check availableToWrite() > 0 before calling this function.
129      * \param byte The value of the byte to write.
130      */
writeByte(uint8_t byte)131     void writeByte(uint8_t byte) {
132         if (availableToWrite() == 0) {
133             return;
134         }
135         mBuffer[mHeadPosition++] = byte;
136         if (mHeadPosition == mBuffer.size()) {
137             mHeadPosition = 0;
138         }
139         mFull = (mHeadPosition == mTailPosition);
140     }
141 
142     /**
143      * Clear the data stored in this instance.
144      */
clear()145     void clear() {
146         mHeadPosition = 0;
147         mTailPosition = 0;
148         mFull = false;
149     }
150 
151     /**
152      * \brief The number of bytes stored in this instance.
153      * \return The number of bytes stored.
154      */
availableToRead()155     size_t availableToRead() const {
156         if (mFull) {
157             return mBuffer.size();
158         }
159         return (mHeadPosition >= mTailPosition) ? (mHeadPosition - mTailPosition)
160                 : (mHeadPosition - mTailPosition + mBuffer.size());
161     }
162 
163     /**
164      * \brief The free space remaining that can be written into before buffer is full.
165      * \return The number of bytes of free space.
166      */
availableToWrite()167     size_t availableToWrite() const {
168         return mBuffer.size() - availableToRead();
169     }
170 
171     /**
172      * \brief Is there any data stored in this instance?
173      * \return true if there is no data stored in this instance, otherwise false.
174      */
empty()175     bool empty() const {
176         return !mFull && mHeadPosition == mTailPosition;
177     }
178 
179  private:
180     std::vector<uint8_t> mBuffer;
181     size_t mHeadPosition = 0u;
182     size_t mTailPosition = 0u;
183     bool mFull = false;
184 };
185 
186 }  // namespace android::audio_utils
187