1 /*
2  * Copyright 2015 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 #include <algorithm>
18 #include <memory.h>
19 #include <stdint.h>
20 
21 #include "fifo/FifoControllerBase.h"
22 #include "fifo/FifoController.h"
23 #include "fifo/FifoControllerIndirect.h"
24 #include "fifo/FifoBuffer.h"
25 
26 namespace oboe {
27 
FifoBuffer(uint32_t bytesPerFrame,uint32_t capacityInFrames)28 FifoBuffer::FifoBuffer(uint32_t bytesPerFrame, uint32_t capacityInFrames)
29         : mBytesPerFrame(bytesPerFrame)
30         , mStorage(nullptr)
31         , mFramesReadCount(0)
32         , mFramesUnderrunCount(0)
33 {
34     mFifo = std::make_unique<FifoController>(capacityInFrames);
35     // allocate buffer
36     int32_t bytesPerBuffer = bytesPerFrame * capacityInFrames;
37     mStorage = new uint8_t[bytesPerBuffer];
38     mStorageOwned = true;
39 }
40 
FifoBuffer(uint32_t bytesPerFrame,uint32_t capacityInFrames,std::atomic<uint64_t> * readCounterAddress,std::atomic<uint64_t> * writeCounterAddress,uint8_t * dataStorageAddress)41 FifoBuffer::FifoBuffer( uint32_t  bytesPerFrame,
42                         uint32_t  capacityInFrames,
43                         std::atomic<uint64_t>  *readCounterAddress,
44                         std::atomic<uint64_t>  *writeCounterAddress,
45                         uint8_t  *dataStorageAddress
46                         )
47         : mBytesPerFrame(bytesPerFrame)
48         , mStorage(dataStorageAddress)
49         , mFramesReadCount(0)
50         , mFramesUnderrunCount(0)
51 {
52     mFifo = std::make_unique<FifoControllerIndirect>(capacityInFrames,
53                                        readCounterAddress,
54                                        writeCounterAddress);
55     mStorage = dataStorageAddress;
56     mStorageOwned = false;
57 }
58 
~FifoBuffer()59 FifoBuffer::~FifoBuffer() {
60     if (mStorageOwned) {
61         delete[] mStorage;
62     }
63 }
64 
convertFramesToBytes(int32_t frames)65 int32_t FifoBuffer::convertFramesToBytes(int32_t frames) {
66     return frames * mBytesPerFrame;
67 }
68 
read(void * buffer,int32_t numFrames)69 int32_t FifoBuffer::read(void *buffer, int32_t numFrames) {
70     if (numFrames <= 0) {
71         return 0;
72     }
73     // safe because numFrames is guaranteed positive
74     uint32_t framesToRead = static_cast<uint32_t>(numFrames);
75     uint32_t framesAvailable = mFifo->getFullFramesAvailable();
76     framesToRead = std::min(framesToRead, framesAvailable);
77 
78     uint32_t readIndex = mFifo->getReadIndex(); // ranges 0 to capacity
79     uint8_t *destination = reinterpret_cast<uint8_t *>(buffer);
80     uint8_t *source = &mStorage[convertFramesToBytes(readIndex)];
81     if ((readIndex + framesToRead) > mFifo->getFrameCapacity()) {
82         // read in two parts, first part here is at the end of the mStorage buffer
83         int32_t frames1 = static_cast<int32_t>(mFifo->getFrameCapacity() - readIndex);
84         int32_t numBytes = convertFramesToBytes(frames1);
85         if (numBytes < 0) {
86             return static_cast<int32_t>(Result::ErrorOutOfRange);
87         }
88         memcpy(destination, source, static_cast<size_t>(numBytes));
89         destination += numBytes;
90         // read second part, which is at the beginning of mStorage
91         source = &mStorage[0];
92         int32_t frames2 = static_cast<uint32_t>(framesToRead - frames1);
93         numBytes = convertFramesToBytes(frames2);
94         if (numBytes < 0) {
95             return static_cast<int32_t>(Result::ErrorOutOfRange);
96         }
97         memcpy(destination, source, static_cast<size_t>(numBytes));
98     } else {
99         // just read in one shot
100         int32_t numBytes = convertFramesToBytes(framesToRead);
101         if (numBytes < 0) {
102             return static_cast<int32_t>(Result::ErrorOutOfRange);
103         }
104         memcpy(destination, source, static_cast<size_t>(numBytes));
105     }
106     mFifo->advanceReadIndex(framesToRead);
107 
108     return framesToRead;
109 }
110 
write(const void * buffer,int32_t numFrames)111 int32_t FifoBuffer::write(const void *buffer, int32_t numFrames) {
112     if (numFrames <= 0) {
113         return 0;
114     }
115     // Guaranteed positive.
116     uint32_t framesToWrite = static_cast<uint32_t>(numFrames);
117     uint32_t framesAvailable = mFifo->getEmptyFramesAvailable();
118     framesToWrite = std::min(framesToWrite, framesAvailable);
119 
120     uint32_t writeIndex = mFifo->getWriteIndex();
121     int byteIndex = convertFramesToBytes(writeIndex);
122     const uint8_t *source = reinterpret_cast<const uint8_t *>(buffer);
123     uint8_t *destination = &mStorage[byteIndex];
124     if ((writeIndex + framesToWrite) > mFifo->getFrameCapacity()) {
125         // write in two parts, first part here
126         int32_t frames1 = static_cast<uint32_t>(mFifo->getFrameCapacity() - writeIndex);
127         int32_t numBytes = convertFramesToBytes(frames1);
128         if (numBytes < 0) {
129             return static_cast<int32_t>(Result::ErrorOutOfRange);
130         }
131         memcpy(destination, source, static_cast<size_t>(numBytes));
132         // read second part
133         source += convertFramesToBytes(frames1);
134         destination = &mStorage[0];
135         int frames2 = static_cast<uint32_t>(framesToWrite - frames1);
136         numBytes = convertFramesToBytes(frames2);
137         if (numBytes < 0) {
138             return static_cast<int32_t>(Result::ErrorOutOfRange);
139         }
140         memcpy(destination, source, static_cast<size_t>(numBytes));
141     } else {
142         // just write in one shot
143         int32_t numBytes = convertFramesToBytes(framesToWrite);
144         if (numBytes < 0) {
145             return static_cast<int32_t>(Result::ErrorOutOfRange);
146         }
147         memcpy(destination, source, static_cast<size_t>(numBytes));
148     }
149     mFifo->advanceWriteIndex(framesToWrite);
150 
151     return framesToWrite;
152 }
153 
readNow(void * buffer,int32_t numFrames)154 int32_t FifoBuffer::readNow(void *buffer, int32_t numFrames) {
155     int32_t framesRead = read(buffer, numFrames);
156     if (framesRead < 0) {
157         return framesRead;
158     }
159     int32_t framesLeft = numFrames - framesRead;
160     mFramesReadCount += framesRead;
161     mFramesUnderrunCount += framesLeft;
162     // Zero out any samples we could not set.
163     if (framesLeft > 0) {
164         uint8_t *destination = reinterpret_cast<uint8_t *>(buffer);
165         destination += convertFramesToBytes(framesRead); // point to first byte not set
166         int32_t bytesToZero = convertFramesToBytes(framesLeft);
167         memset(destination, 0, static_cast<size_t>(bytesToZero));
168     }
169 
170     return framesRead;
171 }
172 
173 
getBufferCapacityInFrames() const174 uint32_t FifoBuffer::getBufferCapacityInFrames() const {
175     return mFifo->getFrameCapacity();
176 }
177 
178 } // namespace oboe
179