1 /*
2      File: CABufferList.h
3  Abstract:  Part of CoreAudio Utility Classes
4   Version: 1.01
5 
6  Disclaimer: IMPORTANT:  This Apple software is supplied to you by Apple
7  Inc. ("Apple") in consideration of your agreement to the following
8  terms, and your use, installation, modification or redistribution of
9  this Apple software constitutes acceptance of these terms.  If you do
10  not agree with these terms, please do not use, install, modify or
11  redistribute this Apple software.
12 
13  In consideration of your agreement to abide by the following terms, and
14  subject to these terms, Apple grants you a personal, non-exclusive
15  license, under Apple's copyrights in this original Apple software (the
16  "Apple Software"), to use, reproduce, modify and redistribute the Apple
17  Software, with or without modifications, in source and/or binary forms;
18  provided that if you redistribute the Apple Software in its entirety and
19  without modifications, you must retain this notice and the following
20  text and disclaimers in all such redistributions of the Apple Software.
21  Neither the name, trademarks, service marks or logos of Apple Inc. may
22  be used to endorse or promote products derived from the Apple Software
23  without specific prior written permission from Apple.  Except as
24  expressly stated in this notice, no other rights or licenses, express or
25  implied, are granted by Apple herein, including but not limited to any
26  patent rights that may be infringed by your derivative works or by other
27  works in which the Apple Software may be incorporated.
28 
29  The Apple Software is provided by Apple on an "AS IS" basis.  APPLE
30  MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
31  THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS
32  FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
33  OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
34 
35  IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
36  OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
37  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
38  INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
39  MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
40  AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),
41  STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
42  POSSIBILITY OF SUCH DAMAGE.
43 
44  Copyright (C) 2012 Apple Inc. All Rights Reserved.
45 
46 */
47 #ifndef __CABufferList_h__
48 #define __CABufferList_h__
49 
50 #include <stddef.h>
51 #include "CAStreamBasicDescription.h"
52 #include "CAXException.h"
53 
54 void CAShowAudioBufferList(const AudioBufferList &abl, int framesToPrint, const AudioStreamBasicDescription &fmt, const char *label=NULL);
55 void CAShowAudioBufferList(const AudioBufferList &abl, int framesToPrint, int wordSize, const char *label=NULL);
56 extern "C" void CAShowAudioBufferList(const AudioBufferList *abl, int framesToPrint, int wordSize);
57 extern "C" int CrashIfClientProvidedBogusAudioBufferList(const AudioBufferList *abl, bool nullOK=false);
58 
59 /* ____________________________________________________________________________
60 //	CABufferList - variable length buffer list
61 
62 	This class is designed for use in non-simplistic cases. For AudioUnits, AUBufferList
63 	is preferred.
64 
65 	CABufferList can be used in one of two ways:
66 		- as mutable pointers into non-owned memory
67 		- as an immutable array of buffers (owns its own memory).
68 
69  	All buffers are assumed to have the same format (number of channels, word size), so that
70 		we can assume their mDataByteSizes are all the same.
71 ____________________________________________________________________________ */
72 class CABufferList {
73 public:
new(size_t,int nBuffers)74 	void *	operator new(size_t /*size*/, int nBuffers) {
75 				return ::operator new(sizeof(CABufferList) + (nBuffers-1) * sizeof(AudioBuffer));
76 			}
New(const char * name,const CAStreamBasicDescription & format)77 	static CABufferList *	New(const char *name, const CAStreamBasicDescription &format)
78 	{
79 		UInt32 numBuffers = format.NumberChannelStreams(), channelsPerBuffer = format.NumberInterleavedChannels();
80 		return new(numBuffers) CABufferList(name, numBuffers, channelsPerBuffer);
81 	}
New(const CAStreamBasicDescription & format)82 	static CABufferList *	New(const CAStreamBasicDescription &format) { return New("", format); }
83 
84 	static CABufferList *	New(UInt32 numBuffers, UInt32 channelsPerBuffer, const char *name="") {
85 		return new(numBuffers) CABufferList(name, numBuffers, channelsPerBuffer);
86 	}
87 
88 protected:
CABufferList(const char * name,UInt32 numBuffers,UInt32 channelsPerBuffer)89 	CABufferList(const char *name, UInt32 numBuffers, UInt32 channelsPerBuffer) :
90 		mName(name),
91 		mBufferMemory(NULL),
92 		mBufferCapacity(0)
93 	{
94 		//XAssert(numBuffers > 0 /*&& channelsPerBuffer > 0*/);
95 		mABL.mNumberBuffers = numBuffers;
96 		AudioBuffer *buf = mABL.mBuffers;
97 		for (UInt32 i = mABL.mNumberBuffers; i--; ++buf) {
98 			buf->mNumberChannels = channelsPerBuffer;
99 			buf->mDataByteSize = 0;
100 			buf->mData = NULL;
101 		}
102 	}
103 
104 public:
~CABufferList()105 	~CABufferList()
106 	{
107 		if (mBufferMemory)
108 			delete[] mBufferMemory;
109 	}
110 
Name()111 	const char *				Name() { return mName; }
112 
GetBufferList()113 	const AudioBufferList &		GetBufferList() const { return mABL; }
114 
GetModifiableBufferList()115 	AudioBufferList &			GetModifiableBufferList() { return _GetBufferList(); }
116 
GetNumberBuffers()117 	UInt32		GetNumberBuffers() const { return mABL.mNumberBuffers; }
118 
GetNumBytes()119 	UInt32		GetNumBytes() const
120 	{
121 		return mABL.mBuffers[0].mDataByteSize;
122 	}
123 
SetBytes(UInt32 nBytes,void * data)124 	void		SetBytes(UInt32 nBytes, void *data)
125 	{
126 		VerifyNotTrashingOwnedBuffer();
127 		XAssert(mABL.mNumberBuffers == 1);
128 		mABL.mBuffers[0].mDataByteSize = nBytes;
129 		mABL.mBuffers[0].mData = data;
130 	}
131 
CopyAllFrom(CABufferList * srcbl,CABufferList * ptrbl)132 	void		CopyAllFrom(CABufferList *srcbl, CABufferList *ptrbl)
133 					// copies bytes from srcbl
134 					// make ptrbl reflect the length copied
135 					// note that srcbl may be same as ptrbl!
136 	{
137 		// Note that this buffer *can* own memory and its pointers/lengths are not
138 		// altered; only its buffer contents, which are copied from srcbl.
139 		// The pointers/lengths in ptrbl are updated to reflect the addresses/lengths
140 		// of the copied data, and srcbl's contents are consumed.
141 		ptrbl->VerifyNotTrashingOwnedBuffer();
142 		UInt32 nBytes = srcbl->GetNumBytes();
143 		AudioBuffer *mybuf = mABL.mBuffers, *srcbuf = srcbl->mABL.mBuffers,
144 					*ptrbuf = ptrbl->mABL.mBuffers;
145 		for (UInt32 i = mABL.mNumberBuffers; i--; ++mybuf, ++srcbuf, ++ptrbuf) {
146 			memmove(mybuf->mData, srcbuf->mData, srcbuf->mDataByteSize);
147 			ptrbuf->mData = mybuf->mData;
148 			ptrbuf->mDataByteSize = srcbuf->mDataByteSize;
149 		}
150 		if (srcbl != ptrbl)
151 			srcbl->BytesConsumed(nBytes);
152 	}
153 
154 	// copies data from another buffer list.
CopyDataFrom(const AudioBufferList & other)155 	void		CopyDataFrom(const AudioBufferList &other)
156 	{
157 		for (unsigned i = 0; i < other.mNumberBuffers; ++i) {
158 			XAssert(mBufferCapacity == 0 || other.mBuffers[i].mDataByteSize <= mBufferCapacity);
159 			memcpy(mABL.mBuffers[i].mData, other.mBuffers[i].mData,
160 				mABL.mBuffers[i].mDataByteSize = other.mBuffers[i].mDataByteSize);
161 		}
162 	}
163 
AppendFrom(CABufferList * blp,UInt32 nBytes)164 	void		AppendFrom(CABufferList *blp, UInt32 nBytes)
165 	{
166 		// this may mutate a buffer that owns memory.
167 		AudioBuffer *mybuf = mABL.mBuffers, *srcbuf = blp->mABL.mBuffers;
168 		for (UInt32 i = mABL.mNumberBuffers; i--; ++mybuf, ++srcbuf) {
169 			XAssert(nBytes <= srcbuf->mDataByteSize);
170 			XAssert(mBufferCapacity == 0 || mybuf->mDataByteSize + nBytes <= mBufferCapacity);
171 			memcpy((Byte *)mybuf->mData + mybuf->mDataByteSize, srcbuf->mData, nBytes);
172 			mybuf->mDataByteSize += nBytes;
173 		}
174 		blp->BytesConsumed(nBytes);
175 	}
176 
PadWithZeroes(UInt32 desiredBufferSize)177 	void		PadWithZeroes(UInt32 desiredBufferSize)
178 					// for cases where an algorithm (e.g. SRC) requires some
179 					// padding to create silence following end-of-file
180 	{
181 		XAssert(mBufferCapacity == 0 || desiredBufferSize <= mBufferCapacity);
182 		if (GetNumBytes() > desiredBufferSize) return;
183 		AudioBuffer *buf = mABL.mBuffers;
184 		for (UInt32 i = mABL.mNumberBuffers; i--; ++buf) {
185 			memset((Byte *)buf->mData + buf->mDataByteSize, 0, desiredBufferSize - buf->mDataByteSize);
186 			buf->mDataByteSize = desiredBufferSize;
187 		}
188 	}
189 
SetToZeroes(UInt32 nBytes)190 	void		SetToZeroes(UInt32 nBytes)
191 	{
192 		XAssert(mBufferCapacity == 0 || nBytes <= mBufferCapacity);
193 		AudioBuffer *buf = mABL.mBuffers;
194 		for (UInt32 i = mABL.mNumberBuffers; i--; ++buf) {
195 			memset((Byte *)buf->mData, 0, nBytes);
196 			buf->mDataByteSize = nBytes;
197 		}
198 	}
199 
Reset()200 	void		Reset()
201 	{
202 		DeallocateBuffers();
203 	}
204 
SameDataAs(const CABufferList * anotherBufferList)205 	Boolean		SameDataAs(const CABufferList* anotherBufferList)
206 	{
207 		// check to see if two buffer lists point to the same memory.
208 		if (mABL.mNumberBuffers != anotherBufferList->mABL.mNumberBuffers) return false;
209 
210 		for (UInt32 i = 0; i < mABL.mNumberBuffers; ++i) {
211 			if (mABL.mBuffers[i].mData != anotherBufferList->mABL.mBuffers[i].mData) return false;
212 		}
213 		return true;
214 	}
215 
BytesConsumed(UInt32 nBytes)216 	void		BytesConsumed(UInt32 nBytes)
217 					// advance buffer pointers, decrease buffer sizes
218 	{
219 		VerifyNotTrashingOwnedBuffer();
220 		AudioBuffer *buf = mABL.mBuffers;
221 		for (UInt32 i = mABL.mNumberBuffers; i--; ++buf) {
222 			XAssert(nBytes <= buf->mDataByteSize);
223 			buf->mData = (Byte *)buf->mData + nBytes;
224 			buf->mDataByteSize -= nBytes;
225 		}
226 	}
227 
SetFrom(const AudioBufferList * abl)228 	void		SetFrom(const AudioBufferList *abl)
229 	{
230 		VerifyNotTrashingOwnedBuffer();
231 		memcpy(&_GetBufferList(), abl, (char *)&abl->mBuffers[abl->mNumberBuffers] - (char *)abl);
232 	}
233 
SetFrom(const CABufferList * blp)234 	void		SetFrom(const CABufferList *blp)
235 	{
236 		SetFrom(&blp->GetBufferList());
237 	}
238 
SetFrom(const AudioBufferList * abl,UInt32 nBytes)239 	void		SetFrom(const AudioBufferList *abl, UInt32 nBytes)
240 	{
241 		VerifyNotTrashingOwnedBuffer();
242 		AudioBuffer *mybuf = mABL.mBuffers;
243 		const AudioBuffer *srcbuf = abl->mBuffers;
244 		for (UInt32 i = mABL.mNumberBuffers; i--; ++mybuf, ++srcbuf) {
245 			mybuf->mNumberChannels = srcbuf->mNumberChannels;
246 			mybuf->mDataByteSize = nBytes;
247 			mybuf->mData = srcbuf->mData;
248 		}
249 	}
250 
SetFrom(const CABufferList * blp,UInt32 nBytes)251 	void		SetFrom(const CABufferList *blp, UInt32 nBytes)
252 	{
253 		SetFrom(&blp->GetBufferList(), nBytes);
254 	}
255 
ToAudioBufferList(AudioBufferList * abl)256 	AudioBufferList *	ToAudioBufferList(AudioBufferList *abl) const
257 	{
258 		memcpy(abl, &GetBufferList(), (char *)&abl->mBuffers[mABL.mNumberBuffers] - (char *)abl);
259 		return abl;
260 	}
261 
262 	void		AllocateBuffers(UInt32 nBytes);
263 	void		AllocateBuffersAndCopyFrom(UInt32 nBytes, CABufferList *inCopyFromList, CABufferList *inSetPtrList);
264 
265 	void		DeallocateBuffers();
266 
267 	void		UseExternalBuffer(Byte *ptr, UInt32 nBytes);
268 
AdvanceBufferPointers(UInt32 nBytes)269 	void		AdvanceBufferPointers(UInt32 nBytes) // $$$ ReducingSize
270 					// this is for bufferlists that function simply as
271 					// an array of pointers into another bufferlist, being advanced,
272 					// as in RenderOutput implementations
273 	{
274 		VerifyNotTrashingOwnedBuffer();
275 		AudioBuffer *buf = mABL.mBuffers;
276 		for (UInt32 i = mABL.mNumberBuffers; i--; ++buf) {
277 			buf->mData = (Byte *)buf->mData + nBytes;
278 			buf->mDataByteSize -= nBytes;
279 		}
280 	}
281 
SetNumBytes(UInt32 nBytes)282 	void		SetNumBytes(UInt32 nBytes)
283 	{
284 		XAssert(mBufferCapacity == 0 || nBytes <= mBufferCapacity);
285 		AudioBuffer *buf = mABL.mBuffers;
286 		for (UInt32 i = mABL.mNumberBuffers; i--; ++buf)
287 			buf->mDataByteSize = nBytes;
288 	}
289 
290 	void		Print(const char *label=NULL, int nframes=0, int wordSize=0) const
291 	{
292 		if (label == NULL)
293 			label = mName;
294 		printf("%s - ", label);
295 		CAShowAudioBufferList(&GetBufferList(), nframes, wordSize);
296 		if (mBufferMemory)
297 			printf("  owned memory @ 0x%p:\n", mBufferMemory);
298 	}
299 
GetCapacityBytes()300 	UInt32		GetCapacityBytes() const { return mBufferCapacity; }
301 
302 protected:
_GetBufferList()303 	AudioBufferList &	_GetBufferList() { return mABL; }	// use with care
304 							// if we make this public, then we lose ability to call VerifyNotTrashingOwnedBuffer
VerifyNotTrashingOwnedBuffer()305 	void				VerifyNotTrashingOwnedBuffer()
306 	{
307 		// This needs to be called from places where we are modifying the buffer pointers.
308 		// It's an error to modify the buffer pointers or lengths if we own the buffer memory.
309 		XAssert(mBufferMemory == NULL);
310 	}
311 
312 	const char *						mName;	// for debugging
313 	Byte *								mBufferMemory;
314 	UInt32								mBufferCapacity;	// max mDataByteSize of each buffer
315 	AudioBufferList						mABL;
316 	// don't add anything here
317 };
318 
319 #endif // __CABufferList_h__
320