1 /*
2 Copyright (C) 2016 Apple Inc. All Rights Reserved.
3 See LICENSE.txt for this sample’s licensing information
4 
5 Abstract:
6 Part of Core Audio Public Utility Classes
7 */
8 
9 #ifndef __CABufferList_h__
10 #define __CABufferList_h__
11 
12 #include <stddef.h>
13 #include "CAStreamBasicDescription.h"
14 #include "CAXException.h"
15 
16 void CAShowAudioBufferList(const AudioBufferList &abl, int framesToPrint, const AudioStreamBasicDescription &fmt, const char *label=NULL);
17 void CAShowAudioBufferList(const AudioBufferList &abl, int framesToPrint, int wordSize, const char *label=NULL);
18 extern "C" void CAShowAudioBufferList(const AudioBufferList *abl, int framesToPrint, int wordSize);
19 extern "C" int CrashIfClientProvidedBogusAudioBufferList(const AudioBufferList *abl, bool nullOK=false);
20 
21 /* ____________________________________________________________________________
22 //	CABufferList - variable length buffer list
23 
24 	This class is designed for use in non-simplistic cases. For AudioUnits, AUBufferList
25 	is preferred.
26 
27 	CABufferList can be used in one of two ways:
28 		- as mutable pointers into non-owned memory
29 		- as an immutable array of buffers (owns its own memory).
30 
31  	All buffers are assumed to have the same format (number of channels, word size), so that
32 		we can assume their mDataByteSizes are all the same.
33 ____________________________________________________________________________ */
34 class CABufferList {
35 public:
new(size_t,int nBuffers)36 	void *	operator new(size_t /*size*/, int nBuffers) {
37 				return ::operator new(sizeof(CABufferList) + (nBuffers-1) * sizeof(AudioBuffer));
38 			}
New(const char * name,const CAStreamBasicDescription & format)39 	static CABufferList *	New(const char *name, const CAStreamBasicDescription &format)
40 	{
41 		UInt32 numBuffers = format.NumberChannelStreams(), channelsPerBuffer = format.NumberInterleavedChannels();
42 		return new(numBuffers) CABufferList(name, numBuffers, channelsPerBuffer);
43 	}
New(const CAStreamBasicDescription & format)44 	static CABufferList *	New(const CAStreamBasicDescription &format) { return New("", format); }
45 
46 	static CABufferList *	New(UInt32 numBuffers, UInt32 channelsPerBuffer, const char *name="") {
47 		return new(numBuffers) CABufferList(name, numBuffers, channelsPerBuffer);
48 	}
49 
50 protected:
CABufferList(const char * name,UInt32 numBuffers,UInt32 channelsPerBuffer)51 	CABufferList(const char *name, UInt32 numBuffers, UInt32 channelsPerBuffer) :
52 		mName(name),
53 		mBufferMemory(NULL),
54 		mBufferCapacity(0)
55 	{
56 		//XAssert(numBuffers > 0 /*&& channelsPerBuffer > 0*/);
57 		mABL.mNumberBuffers = numBuffers;
58 		AudioBuffer *buf = mABL.mBuffers;
59 		for (UInt32 i = mABL.mNumberBuffers; i--; ++buf) {
60 			buf->mNumberChannels = channelsPerBuffer;
61 			buf->mDataByteSize = 0;
62 			buf->mData = NULL;
63 		}
64 	}
65 
66 public:
~CABufferList()67 	~CABufferList()
68 	{
69 		if (mBufferMemory)
70 			delete[] mBufferMemory;
71 	}
72 
Name()73 	const char *				Name() { return mName; }
74 
GetBufferList()75 	const AudioBufferList &		GetBufferList() const { return mABL; }
76 
GetModifiableBufferList()77 	AudioBufferList &			GetModifiableBufferList() { return _GetBufferList(); }
78 
GetNumberBuffers()79 	UInt32		GetNumberBuffers() const { return mABL.mNumberBuffers; }
80 
GetNumBytes()81 	UInt32		GetNumBytes() const
82 	{
83 		return mABL.mBuffers[0].mDataByteSize;
84 	}
85 
SetBytes(UInt32 nBytes,void * data)86 	void		SetBytes(UInt32 nBytes, void *data)
87 	{
88 		VerifyNotTrashingOwnedBuffer();
89 		XAssert(mABL.mNumberBuffers == 1);
90 		mABL.mBuffers[0].mDataByteSize = nBytes;
91 		mABL.mBuffers[0].mData = data;
92 	}
93 
CopyAllFrom(CABufferList * srcbl,CABufferList * ptrbl)94 	void		CopyAllFrom(CABufferList *srcbl, CABufferList *ptrbl)
95 					// copies bytes from srcbl
96 					// make ptrbl reflect the length copied
97 					// note that srcbl may be same as ptrbl!
98 	{
99 		// Note that this buffer *can* own memory and its pointers/lengths are not
100 		// altered; only its buffer contents, which are copied from srcbl.
101 		// The pointers/lengths in ptrbl are updated to reflect the addresses/lengths
102 		// of the copied data, and srcbl's contents are consumed.
103 		ptrbl->VerifyNotTrashingOwnedBuffer();
104 		UInt32 nBytes = srcbl->GetNumBytes();
105 		AudioBuffer *mybuf = mABL.mBuffers, *srcbuf = srcbl->mABL.mBuffers,
106 					*ptrbuf = ptrbl->mABL.mBuffers;
107 		for (UInt32 i = mABL.mNumberBuffers; i--; ++mybuf, ++srcbuf, ++ptrbuf) {
108 			memmove(mybuf->mData, srcbuf->mData, srcbuf->mDataByteSize);
109 			ptrbuf->mData = mybuf->mData;
110 			ptrbuf->mDataByteSize = srcbuf->mDataByteSize;
111 		}
112 		if (srcbl != ptrbl)
113 			srcbl->BytesConsumed(nBytes);
114 	}
115 
116 	// copies data from another buffer list.
CopyDataFrom(const AudioBufferList & other)117 	void		CopyDataFrom(const AudioBufferList &other)
118 	{
119 		for (unsigned i = 0; i < other.mNumberBuffers; ++i) {
120 			XAssert(mBufferCapacity == 0 || other.mBuffers[i].mDataByteSize <= mBufferCapacity);
121 			memcpy(mABL.mBuffers[i].mData, other.mBuffers[i].mData,
122 				mABL.mBuffers[i].mDataByteSize = other.mBuffers[i].mDataByteSize);
123 		}
124 	}
125 
AppendFrom(CABufferList * blp,UInt32 nBytes)126 	void		AppendFrom(CABufferList *blp, UInt32 nBytes)
127 	{
128 		// this may mutate a buffer that owns memory.
129 		AudioBuffer *mybuf = mABL.mBuffers, *srcbuf = blp->mABL.mBuffers;
130 		for (UInt32 i = mABL.mNumberBuffers; i--; ++mybuf, ++srcbuf) {
131 			XAssert(nBytes <= srcbuf->mDataByteSize);
132 			XAssert(mBufferCapacity == 0 || mybuf->mDataByteSize + nBytes <= mBufferCapacity);
133 			memcpy((Byte *)mybuf->mData + mybuf->mDataByteSize, srcbuf->mData, nBytes);
134 			mybuf->mDataByteSize += nBytes;
135 		}
136 		blp->BytesConsumed(nBytes);
137 	}
138 
PadWithZeroes(UInt32 desiredBufferSize)139 	void		PadWithZeroes(UInt32 desiredBufferSize)
140 					// for cases where an algorithm (e.g. SRC) requires some
141 					// padding to create silence following end-of-file
142 	{
143 		XAssert(mBufferCapacity == 0 || desiredBufferSize <= mBufferCapacity);
144 		if (GetNumBytes() > desiredBufferSize) return;
145 		AudioBuffer *buf = mABL.mBuffers;
146 		for (UInt32 i = mABL.mNumberBuffers; i--; ++buf) {
147 			memset((Byte *)buf->mData + buf->mDataByteSize, 0, desiredBufferSize - buf->mDataByteSize);
148 			buf->mDataByteSize = desiredBufferSize;
149 		}
150 	}
151 
SetToZeroes(UInt32 nBytes)152 	void		SetToZeroes(UInt32 nBytes)
153 	{
154 		XAssert(mBufferCapacity == 0 || nBytes <= mBufferCapacity);
155 		AudioBuffer *buf = mABL.mBuffers;
156 		for (UInt32 i = mABL.mNumberBuffers; i--; ++buf) {
157 			memset((Byte *)buf->mData, 0, nBytes);
158 			buf->mDataByteSize = nBytes;
159 		}
160 	}
161 
Reset()162 	void		Reset()
163 	{
164 		DeallocateBuffers();
165 	}
166 
SameDataAs(const CABufferList * anotherBufferList)167 	Boolean		SameDataAs(const CABufferList* anotherBufferList)
168 	{
169 		// check to see if two buffer lists point to the same memory.
170 		if (mABL.mNumberBuffers != anotherBufferList->mABL.mNumberBuffers) return false;
171 
172 		for (UInt32 i = 0; i < mABL.mNumberBuffers; ++i) {
173 			if (mABL.mBuffers[i].mData != anotherBufferList->mABL.mBuffers[i].mData) return false;
174 		}
175 		return true;
176 	}
177 
BytesConsumed(UInt32 nBytes)178 	void		BytesConsumed(UInt32 nBytes)
179 					// advance buffer pointers, decrease buffer sizes
180 	{
181 		VerifyNotTrashingOwnedBuffer();
182 		AudioBuffer *buf = mABL.mBuffers;
183 		for (UInt32 i = mABL.mNumberBuffers; i--; ++buf) {
184 			XAssert(nBytes <= buf->mDataByteSize);
185 			buf->mData = (Byte *)buf->mData + nBytes;
186 			buf->mDataByteSize -= nBytes;
187 		}
188 	}
189 
SetFrom(const AudioBufferList * abl)190 	void		SetFrom(const AudioBufferList *abl)
191 	{
192 		VerifyNotTrashingOwnedBuffer();
193 		memcpy(&_GetBufferList(), abl, (char *)&abl->mBuffers[abl->mNumberBuffers] - (char *)abl);
194 	}
195 
SetFrom(const CABufferList * blp)196 	void		SetFrom(const CABufferList *blp)
197 	{
198 		SetFrom(&blp->GetBufferList());
199 	}
200 
SetFrom(const AudioBufferList * abl,UInt32 nBytes)201 	void		SetFrom(const AudioBufferList *abl, UInt32 nBytes)
202 	{
203 		VerifyNotTrashingOwnedBuffer();
204 		AudioBuffer *mybuf = mABL.mBuffers;
205 		const AudioBuffer *srcbuf = abl->mBuffers;
206 		for (UInt32 i = mABL.mNumberBuffers; i--; ++mybuf, ++srcbuf) {
207 			mybuf->mNumberChannels = srcbuf->mNumberChannels;
208 			mybuf->mDataByteSize = nBytes;
209 			mybuf->mData = srcbuf->mData;
210 		}
211 	}
212 
SetFrom(const CABufferList * blp,UInt32 nBytes)213 	void		SetFrom(const CABufferList *blp, UInt32 nBytes)
214 	{
215 		SetFrom(&blp->GetBufferList(), nBytes);
216 	}
217 
ToAudioBufferList(AudioBufferList * abl)218 	AudioBufferList *	ToAudioBufferList(AudioBufferList *abl) const
219 	{
220 		memcpy(abl, &GetBufferList(), (char *)&abl->mBuffers[mABL.mNumberBuffers] - (char *)abl);
221 		return abl;
222 	}
223 
224 	void		AllocateBuffers(UInt32 nBytes);
225 	void		AllocateBuffersAndCopyFrom(UInt32 nBytes, CABufferList *inCopyFromList, CABufferList *inSetPtrList);
226 
227 	void		DeallocateBuffers();
228 
229 	void		UseExternalBuffer(Byte *ptr, UInt32 nBytes);
230 
AdvanceBufferPointers(UInt32 nBytes)231 	void		AdvanceBufferPointers(UInt32 nBytes) // $$$ ReducingSize
232 					// this is for bufferlists that function simply as
233 					// an array of pointers into another bufferlist, being advanced,
234 					// as in RenderOutput implementations
235 	{
236 		VerifyNotTrashingOwnedBuffer();
237 		AudioBuffer *buf = mABL.mBuffers;
238 		for (UInt32 i = mABL.mNumberBuffers; i--; ++buf) {
239 			buf->mData = (Byte *)buf->mData + nBytes;
240 			buf->mDataByteSize -= nBytes;
241 		}
242 	}
243 
SetNumBytes(UInt32 nBytes)244 	void		SetNumBytes(UInt32 nBytes)
245 	{
246 		XAssert(mBufferCapacity == 0 || nBytes <= mBufferCapacity);
247 		AudioBuffer *buf = mABL.mBuffers;
248 		for (UInt32 i = mABL.mNumberBuffers; i--; ++buf)
249 			buf->mDataByteSize = nBytes;
250 	}
251 
252 	void		Print(const char *label=NULL, int nframes=0, int wordSize=0) const
253 	{
254 		if (label == NULL)
255 			label = mName;
256 		printf("%s - ", label);
257 		CAShowAudioBufferList(&GetBufferList(), nframes, wordSize);
258 		if (mBufferMemory)
259 			printf("  owned memory @ 0x%p:\n", mBufferMemory);
260 	}
261 
GetCapacityBytes()262 	UInt32		GetCapacityBytes() const { return mBufferCapacity; }
263 
264 	template <typename T>
GetData(UInt32 inBuffer)265 	T*			GetData(UInt32 inBuffer) {
266 		return static_cast<T*>(mABL.mBuffers[inBuffer].mData);
267 	}
268 
269 protected:
_GetBufferList()270 	AudioBufferList &	_GetBufferList() { return mABL; }	// use with care
271 							// if we make this public, then we lose ability to call VerifyNotTrashingOwnedBuffer
VerifyNotTrashingOwnedBuffer()272 	void				VerifyNotTrashingOwnedBuffer()
273 	{
274 		// This needs to be called from places where we are modifying the buffer pointers.
275 		// It's an error to modify the buffer pointers or lengths if we own the buffer memory.
276 		XAssert(mBufferMemory == NULL);
277 	}
278 
279 	const char *						mName;	// for debugging
280 	Byte *								mBufferMemory;
281 	UInt32								mBufferCapacity;	// max mDataByteSize of each buffer
282 	AudioBufferList						mABL;
283 	// don't add anything here
284 };
285 
286 #endif // __CABufferList_h__
287