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