41 #include "CARingBuffer.h"
42 #include "CABitOperations.h"
43 #include "CAAutoDisposer.h"
49 #include <libkern/OSAtomic.h>
51 CARingBuffer::CARingBuffer() :
52 mBuffers(NULL), mNumberChannels(0), mCapacityFrames(0), mCapacityBytes(0)
57 CARingBuffer::~CARingBuffer()
63 void CARingBuffer::Allocate(
int nChannels, UInt32 bytesPerFrame, UInt32 capacityFrames)
69 mNumberChannels = nChannels;
70 mBytesPerFrame = bytesPerFrame;
71 mCapacityFrames = capacityFrames;
73 mCapacityBytes = bytesPerFrame * capacityFrames;
76 UInt32 allocSize = (mCapacityBytes +
sizeof(Byte *)) * nChannels;
77 Byte *p = (Byte *)CA_malloc(allocSize);
78 memset(p, 0, allocSize);
79 mBuffers = (Byte **)p;
80 p += nChannels *
sizeof(Byte *);
81 for (
int i = 0; i < nChannels; ++i) {
86 for (UInt32 i = 0; i<kGeneralRingTimeBoundsQueueSize; ++i)
88 mTimeBoundsQueue[i].mStartTime = 0;
89 mTimeBoundsQueue[i].mEndTime = 0;
90 mTimeBoundsQueue[i].mUpdateCounter = 0;
92 mTimeBoundsQueuePtr = 0;
95 void CARingBuffer::Deallocate()
106 inline void ZeroRange(Byte **buffers,
int nchannels,
int offset,
int nbytes)
108 while (--nchannels >= 0) {
109 memset(*buffers + offset, 0, nbytes);
114 inline void StoreABL(Byte **buffers,
int destOffset,
const AudioBufferList *abl,
int srcOffset,
int nbytes)
116 int nchannels = abl->mNumberBuffers;
117 const AudioBuffer *src = abl->mBuffers;
118 while (--nchannels >= 0) {
119 memcpy(*buffers + destOffset, (Byte *)src->mData + srcOffset, nbytes);
125 inline void FetchABL(AudioBufferList *abl,
int destOffset, Byte **buffers,
int srcOffset,
int nbytes)
127 int nchannels = abl->mNumberBuffers;
128 AudioBuffer *dest = abl->mBuffers;
129 while (--nchannels >= 0) {
130 memcpy((Byte *)dest->mData + destOffset, *buffers + srcOffset, nbytes);
136 inline void ZeroABL(AudioBufferList *abl,
int destOffset,
int nbytes)
138 int nBuffers = abl->mNumberBuffers;
139 AudioBuffer *dest = abl->mBuffers;
140 while (--nBuffers >= 0) {
141 memset((Byte *)dest->mData + destOffset, 0, nbytes);
147 CARingBufferError CARingBuffer::Store(
const AudioBufferList *abl, UInt32 framesToWrite, SampleTime startWrite)
149 if (framesToWrite > mCapacityFrames)
150 return kCARingBufferError_TooMuch;
152 SampleTime endWrite = startWrite + framesToWrite;
154 if (startWrite < EndTime()) {
156 SetTimeBounds(startWrite, startWrite);
157 }
else if (endWrite - StartTime() <= mCapacityFrames) {
161 SampleTime newStart = endWrite - mCapacityFrames;
162 SampleTime newEnd = std::max(newStart, EndTime());
163 SetTimeBounds(newStart, newEnd);
167 Byte **buffers = mBuffers;
168 int nchannels = mNumberChannels;
169 int offset0, offset1, nbytes;
170 SampleTime curEnd = EndTime();
172 if (startWrite > curEnd) {
174 offset0 = FrameOffset(curEnd);
175 offset1 = FrameOffset(startWrite);
176 if (offset0 < offset1)
177 ZeroRange(buffers, nchannels, offset0, offset1 - offset0);
179 ZeroRange(buffers, nchannels, offset0, mCapacityBytes - offset0);
180 ZeroRange(buffers, nchannels, 0, offset1);
184 offset0 = FrameOffset(startWrite);
187 offset1 = FrameOffset(endWrite);
188 if (offset0 < offset1)
189 StoreABL(buffers, offset0, abl, 0, offset1 - offset0);
191 nbytes = mCapacityBytes - offset0;
192 StoreABL(buffers, offset0, abl, 0, nbytes);
193 StoreABL(buffers, 0, abl, nbytes, offset1);
197 SetTimeBounds(StartTime(), endWrite);
199 return kCARingBufferError_OK;
202 void CARingBuffer::SetTimeBounds(SampleTime startTime, SampleTime endTime)
204 UInt32 nextPtr = mTimeBoundsQueuePtr + 1;
205 UInt32 index = nextPtr & kGeneralRingTimeBoundsQueueMask;
207 mTimeBoundsQueue[index].mStartTime = startTime;
208 mTimeBoundsQueue[index].mEndTime = endTime;
209 mTimeBoundsQueue[index].mUpdateCounter = nextPtr;
210 CAAtomicCompareAndSwap32Barrier(mTimeBoundsQueuePtr, mTimeBoundsQueuePtr + 1, (SInt32*)&mTimeBoundsQueuePtr);
213 CARingBufferError CARingBuffer::GetTimeBounds(SampleTime &startTime, SampleTime &endTime)
215 for (
int i=0; i<8; ++i)
217 UInt32 curPtr = mTimeBoundsQueuePtr;
218 UInt32 index = curPtr & kGeneralRingTimeBoundsQueueMask;
219 CARingBuffer::TimeBounds* bounds = mTimeBoundsQueue + index;
221 startTime = bounds->mStartTime;
222 endTime = bounds->mEndTime;
223 UInt32 newPtr = bounds->mUpdateCounter;
225 if (newPtr == curPtr)
226 return kCARingBufferError_OK;
228 return kCARingBufferError_CPUOverload;
231 CARingBufferError CARingBuffer::CheckTimeBounds(SampleTime& startRead, SampleTime& endRead)
233 SampleTime startTime, endTime;
235 CARingBufferError err = GetTimeBounds(startTime, endTime);
238 startRead = std::max(startRead, startTime);
239 endRead = std::min(endRead, endTime);
241 if (startRead < startTime)
243 if (endRead > endTime)
244 return kCARingBufferError_TooMuch;
246 if (endRead < startTime)
247 return kCARingBufferError_WayBehind;
249 return kCARingBufferError_SlightlyBehind;
252 if (endRead > endTime)
254 if (startRead > endTime)
255 return kCARingBufferError_WayAhead;
257 return kCARingBufferError_SlightlyAhead;
260 return kCARingBufferError_OK;
263 CARingBufferError worse(CARingBufferError a, CARingBufferError b)
266 CARingBufferError aa = a < 0 ? -a : a;
267 CARingBufferError bb = b < 0 ? -b : b;
268 if (aa > bb)
return a;
272 CARingBufferError CARingBuffer::Fetch(AudioBufferList *abl, UInt32 nFrames, SampleTime startRead,
bool outOfBoundsOK)
274 SampleTime endRead = startRead + nFrames;
276 SampleTime startRead0 = startRead;
277 SampleTime endRead0 = endRead;
280 CARingBufferError err = CheckTimeBounds(startRead, endRead);
281 size = endRead - startRead;
283 if (!outOfBoundsOK)
return err;
284 if (size <= 0)
return err;
287 SInt32 destStartOffset = startRead - startRead0;
288 if (destStartOffset > 0) {
289 ZeroABL(abl, 0, destStartOffset * mBytesPerFrame);
292 SInt32 destEndSize = endRead0 - endRead;
293 if (destEndSize > 0) {
294 ZeroABL(abl, destStartOffset + size, destEndSize * mBytesPerFrame);
297 Byte **buffers = mBuffers;
298 int offset0 = FrameOffset(startRead);
299 int offset1 = FrameOffset(endRead);
302 if (offset0 < offset1) {
303 FetchABL(abl, destStartOffset, buffers, offset0, nbytes = offset1 - offset0);
305 nbytes = mCapacityBytes - offset0;
306 FetchABL(abl, destStartOffset, buffers, offset0, nbytes);
307 FetchABL(abl, destStartOffset + nbytes, buffers, 0, offset1);
311 int nchannels = abl->mNumberBuffers;
312 AudioBuffer *dest = abl->mBuffers;
313 while (--nchannels >= 0)
315 dest->mDataByteSize = nbytes;
320 OSStatus err2 = CheckTimeBounds(startRead, endRead);
321 err2 = worse(err, err2);
322 size = endRead - startRead;
324 if (!outOfBoundsOK)
return err2;
325 if (size <= 0)
return err2;