AUPublic/Utility/AUBuffer.cpp
/* |
Copyright (C) 2016 Apple Inc. All Rights Reserved. |
See LICENSE.txt for this sample’s licensing information |
Abstract: |
Part of Core Audio AUBase Classes |
*/ |
#include "AUBuffer.h" |
#include <stdlib.h> |
AUBufferList::~AUBufferList() |
{ |
Deallocate(); |
if (mPtrs) |
free(mPtrs); |
} |
// a * b + c |
static UInt32 SafeMultiplyAddUInt32(UInt32 a, UInt32 b, UInt32 c) |
{ |
if (a == 0 || b == 0) return c; // prevent zero divide |
if (a > (0xFFFFFFFF - c) / b) |
throw std::bad_alloc(); |
return a * b + c; |
} |
void AUBufferList::Allocate(const CAStreamBasicDescription &format, UInt32 nFrames) |
{ |
UInt32 nStreams; |
if (format.IsInterleaved()) { |
nStreams = 1; |
} else { |
nStreams = format.mChannelsPerFrame; |
} |
// careful -- the I/O thread could be running! |
if (nStreams > mAllocatedStreams) { |
size_t theHeaderSize = sizeof(AudioBufferList) - sizeof(AudioBuffer); |
mPtrs = (AudioBufferList *)CA_realloc(mPtrs, |
SafeMultiplyAddUInt32(nStreams, sizeof(AudioBuffer), theHeaderSize)); |
mAllocatedStreams = nStreams; |
} |
UInt32 bytesPerStream = SafeMultiplyAddUInt32(nFrames, format.mBytesPerFrame, 0xF) & ~0xF; |
UInt32 nBytes = SafeMultiplyAddUInt32(nStreams, bytesPerStream, 0); |
if (nBytes > mAllocatedBytes) { |
if (mExternalMemory) { |
mExternalMemory = false; |
mMemory = NULL; |
} |
mMemory = (Byte *)CA_realloc(mMemory, nBytes); |
mAllocatedBytes = nBytes; |
} |
mAllocatedFrames = nFrames; |
mPtrState = kPtrsInvalid; |
} |
void AUBufferList::Deallocate() |
{ |
mAllocatedStreams = 0; |
mAllocatedFrames = 0; |
mAllocatedBytes = 0; |
// this causes a world of hurt if someone upstream disconnects during I/O (SysSoundGraph) |
/* if (mPtrs) { |
printf("deallocating bufferlist %08X\n", int(mPtrs)); |
free(mPtrs); |
mPtrs = NULL; |
} */ |
if (mMemory) { |
if (mExternalMemory) |
mExternalMemory = false; |
else |
free(mMemory); |
mMemory = NULL; |
} |
mPtrState = kPtrsInvalid; |
} |
AudioBufferList & AUBufferList::PrepareBuffer(const CAStreamBasicDescription &format, UInt32 nFrames) |
{ |
if (nFrames > mAllocatedFrames) |
COMPONENT_THROW(kAudioUnitErr_TooManyFramesToProcess); |
UInt32 nStreams; |
UInt32 channelsPerStream; |
if (format.IsInterleaved()) { |
nStreams = 1; |
channelsPerStream = format.mChannelsPerFrame; |
} else { |
nStreams = format.mChannelsPerFrame; |
channelsPerStream = 1; |
if (nStreams > mAllocatedStreams) |
COMPONENT_THROW(kAudioUnitErr_FormatNotSupported); |
} |
AudioBufferList *abl = mPtrs; |
abl->mNumberBuffers = nStreams; |
AudioBuffer *buf = abl->mBuffers; |
Byte *mem = mMemory; |
UInt32 streamInterval = (mAllocatedFrames * format.mBytesPerFrame + 0xF) & ~0xF; |
UInt32 bytesPerBuffer = nFrames * format.mBytesPerFrame; |
for ( ; nStreams--; ++buf) { |
buf->mNumberChannels = channelsPerStream; |
buf->mData = mem; |
buf->mDataByteSize = bytesPerBuffer; |
mem += streamInterval; |
} |
if (UInt32(mem - mMemory) > mAllocatedBytes) |
COMPONENT_THROW(kAudioUnitErr_TooManyFramesToProcess); |
mPtrState = kPtrsToMyMemory; |
return *mPtrs; |
} |
AudioBufferList & AUBufferList::PrepareNullBuffer(const CAStreamBasicDescription &format, UInt32 nFrames) |
{ |
UInt32 nStreams; |
UInt32 channelsPerStream; |
if (format.IsInterleaved()) { |
nStreams = 1; |
channelsPerStream = format.mChannelsPerFrame; |
} else { |
nStreams = format.mChannelsPerFrame; |
channelsPerStream = 1; |
if (nStreams > mAllocatedStreams) |
COMPONENT_THROW(kAudioUnitErr_FormatNotSupported); |
} |
AudioBufferList *abl = mPtrs; |
abl->mNumberBuffers = nStreams; |
AudioBuffer *buf = abl->mBuffers; |
UInt32 bytesPerBuffer = nFrames * format.mBytesPerFrame; |
for ( ; nStreams--; ++buf) { |
buf->mNumberChannels = channelsPerStream; |
buf->mData = NULL; |
buf->mDataByteSize = bytesPerBuffer; |
} |
mPtrState = kPtrsToExternalMemory; |
return *mPtrs; |
} |
// this should NOT be called while I/O is in process |
void AUBufferList::UseExternalBuffer(const CAStreamBasicDescription &format, const AudioUnitExternalBuffer &buf) |
{ |
UInt32 alignedSize = buf.size & ~0xF; |
if (mMemory != NULL && alignedSize >= mAllocatedBytes) { |
// don't accept the buffer if we already have one and it's big enough |
// if we don't already have one, we don't need one |
Byte *oldMemory = mMemory; |
mMemory = buf.buffer; |
mAllocatedBytes = alignedSize; |
// from Allocate(): nBytes = nStreams * nFrames * format.mBytesPerFrame; |
// thus: nFrames = nBytes / (nStreams * format.mBytesPerFrame) |
mAllocatedFrames = mAllocatedBytes / (format.NumberChannelStreams() * format.mBytesPerFrame); |
mExternalMemory = true; |
free(oldMemory); |
} |
} |
#if DEBUG |
void AUBufferList::PrintBuffer(const char *label, int subscript, const AudioBufferList &abl, UInt32 nFrames, bool asFloats) |
{ |
printf(" %s [%d] 0x%08lX:\n", label, subscript, long(&abl)); |
const AudioBuffer *buf = abl.mBuffers; |
for (UInt32 i = 0; i < abl.mNumberBuffers; ++buf, ++i) { |
printf(" [%2d] %5dbytes %dch @ %p: ", (int)i, (int)buf->mDataByteSize, (int)buf->mNumberChannels, buf->mData); |
if (buf->mData != NULL) { |
UInt32 nSamples = nFrames * buf->mNumberChannels; |
for (UInt32 j = 0; j < nSamples; ++j) { |
if (nSamples > 16 && (j % 16) == 0) |
printf("\n\t"); |
if (asFloats) |
printf(" %6.3f", ((float *)buf->mData)[j]); |
else |
printf(" %08X", (unsigned)((UInt32 *)buf->mData)[j]); |
} |
} |
printf("\n"); |
} |
} |
#endif |
Copyright © 2016 Apple Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2016-02-19