diff options
Diffstat (limited to 'libs/appleutility/CAAudioFile.cpp')
-rw-r--r-- | libs/appleutility/CAAudioFile.cpp | 1241 |
1 files changed, 0 insertions, 1241 deletions
diff --git a/libs/appleutility/CAAudioFile.cpp b/libs/appleutility/CAAudioFile.cpp deleted file mode 100644 index e1e39b0ec9..0000000000 --- a/libs/appleutility/CAAudioFile.cpp +++ /dev/null @@ -1,1241 +0,0 @@ -/* Copyright: © Copyright 2005 Apple Computer, Inc. All rights reserved. - - Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc. - ("Apple") in consideration of your agreement to the following terms, and your - use, installation, modification or redistribution of this Apple software - constitutes acceptance of these terms. If you do not agree with these terms, - please do not use, install, modify or redistribute this Apple software. - - In consideration of your agreement to abide by the following terms, and subject - to these terms, Apple grants you a personal, non-exclusive license, under AppleÕs - copyrights in this original Apple software (the "Apple Software"), to use, - reproduce, modify and redistribute the Apple Software, with or without - modifications, in source and/or binary forms; provided that if you redistribute - the Apple Software in its entirety and without modifications, you must retain - this notice and the following text and disclaimers in all such redistributions of - the Apple Software. Neither the name, trademarks, service marks or logos of - Apple Computer, Inc. may be used to endorse or promote products derived from the - Apple Software without specific prior written permission from Apple. Except as - expressly stated in this notice, no other rights or licenses, express or implied, - are granted by Apple herein, including but not limited to any patent rights that - may be infringed by your derivative works or by other works in which the Apple - Software may be incorporated. - - The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO - WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED - WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR - PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN - COMBINATION WITH YOUR PRODUCTS. - - IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR - CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION - OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT - (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN - ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ -/*============================================================================= - CAAudioFile.cpp - -=============================================================================*/ - -#include "CAAudioFile.h" - -#if !CAAF_USE_EXTAUDIOFILE - -#include "CAXException.h" -#include <algorithm> -#include "CAHostTimeBase.h" -#include "CADebugMacros.h" - -#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__) - #include <AudioToolbox/AudioToolbox.h> -#else - #include <AudioFormat.h> -#endif - -#if DEBUG - //#define VERBOSE_IO 1 - //#define VERBOSE_CONVERTER 1 - //#define VERBOSE_CHANNELMAP 1 - //#define LOG_FUNCTION_ENTRIES 1 - - #if VERBOSE_CHANNELMAP - #include "CAChannelLayouts.h" // this is in Source/Tests/AudioFileTools/Utility - #endif -#endif - -#if LOG_FUNCTION_ENTRIES - class FunctionLogger { - public: - FunctionLogger(const char *name, const char *fmt=NULL, ...) : mName(name) { - Indent(); - printf("-> %s ", name); - if (fmt) { - va_list args; - va_start(args, fmt); - vprintf(fmt, args); - va_end(args); - } - printf("\n"); - ++sIndent; - } - ~FunctionLogger() { - --sIndent; - Indent(); - printf("<- %s\n", mName); - if (sIndent == 0) - printf("\n"); - } - - static void Indent() { - for (int i = sIndent; --i >= 0; ) { - putchar(' '); putchar(' '); - } - } - - const char *mName; - static int sIndent; - }; - int FunctionLogger::sIndent = 0; - - #define LOG_FUNCTION(name, format, ...) FunctionLogger _flog(name, format, ## __VA_ARGS__); -#else - #define LOG_FUNCTION(name, format, foo) -#endif - -static const UInt32 kDefaultIOBufferSizeBytes = 0x10000; - -#if CAAUDIOFILE_PROFILE - #define StartTiming(af, starttime) UInt64 starttime = af->mProfiling ? CAHostTimeBase::GetTheCurrentTime() : 0 - #define ElapsedTime(af, starttime, counter) if (af->mProfiling) counter += (CAHostTimeBase::GetTheCurrentTime() - starttime) -#else - #define StartTiming(af, starttime) - #define ElapsedTime(af, starttime, counter) -#endif - -#define kNoMoreInputRightNow 'nein' - -// _______________________________________________________________________________________ -// -CAAudioFile::CAAudioFile() : - mAudioFile(0), - mUseCache(false), - mFinishingEncoding(false), - mMode(kClosed), - mFileDataOffset(-1), - mFramesToSkipFollowingSeek(0), - - mClientOwnsIOBuffer(false), - mPacketDescs(NULL), - mNumPacketDescs(0), - mConverter(NULL), - mMagicCookie(NULL), - mWriteBufferList(NULL) -#if CAAUDIOFILE_PROFILE - , - mProfiling(false), - mTicksInConverter(0), - mTicksInReadInConverter(0), - mTicksInIO(0), - mInConverter(false) -#endif -{ - mIOBufferList.mBuffers[0].mData = NULL; - mIOBufferList.mBuffers[0].mDataByteSize = 0; - mClientMaxPacketSize = 0; - mIOBufferSizeBytes = kDefaultIOBufferSizeBytes; -} - -// _______________________________________________________________________________________ -// -CAAudioFile::~CAAudioFile() -{ - Close(); -} - -// _______________________________________________________________________________________ -// -void CAAudioFile::Close() -{ - LOG_FUNCTION("CAAudioFile::Close", NULL, NULL); - if (mMode == kClosed) - return; - if (mMode == kWriting) - FlushEncoder(); - CloseConverter(); - if (mAudioFile != 0 && mOwnOpenFile) { - AudioFileClose(mAudioFile); - mAudioFile = 0; - } - if (!mClientOwnsIOBuffer) { - delete[] (Byte *)mIOBufferList.mBuffers[0].mData; - mIOBufferList.mBuffers[0].mData = NULL; - mIOBufferList.mBuffers[0].mDataByteSize = 0; - } - delete[] mPacketDescs; mPacketDescs = NULL; mNumPacketDescs = 0; - delete[] mMagicCookie; mMagicCookie = NULL; - delete mWriteBufferList; mWriteBufferList = NULL; - mMode = kClosed; -} - -// _______________________________________________________________________________________ -// -void CAAudioFile::CloseConverter() -{ - if (mConverter) { -#if VERBOSE_CONVERTER - printf("CAAudioFile %p : CloseConverter\n", this); -#endif - AudioConverterDispose(mConverter); - mConverter = NULL; - } -} - -// ======================================================================================= - -// _______________________________________________________________________________________ -// -void CAAudioFile::Open(const FSRef &fsref) -{ - LOG_FUNCTION("CAAudioFile::Open", "%p", this); - XThrowIf(mMode != kClosed, kExtAudioFileError_InvalidOperationOrder, "file already open"); - mFSRef = fsref; - XThrowIfError(AudioFileOpen(&mFSRef, fsRdPerm, 0, &mAudioFile), "open audio file"); - mOwnOpenFile = true; - mMode = kReading; - GetExistingFileInfo(); -} - -// _______________________________________________________________________________________ -// -void CAAudioFile::Wrap(AudioFileID fileID, bool forWriting) -{ - LOG_FUNCTION("CAAudioFile::Wrap", "%p", this); - XThrowIf(mMode != kClosed, kExtAudioFileError_InvalidOperationOrder, "file already open"); - - mAudioFile = fileID; - mOwnOpenFile = false; - mMode = forWriting ? kPreparingToWrite : kReading; - GetExistingFileInfo(); - if (forWriting) - FileFormatChanged(); -} - -// _______________________________________________________________________________________ -// -void CAAudioFile::CreateNew(const FSRef &parentDir, CFStringRef filename, AudioFileTypeID filetype, const AudioStreamBasicDescription &dataFormat, const AudioChannelLayout *layout) -{ - LOG_FUNCTION("CAAudioFile::CreateNew", "%p", this); - XThrowIf(mMode != kClosed, kExtAudioFileError_InvalidOperationOrder, "file already open"); - - mFileDataFormat = dataFormat; - if (layout) { - mFileChannelLayout = layout; -#if VERBOSE_CHANNELMAP - printf("PrepareNew passed channel layout: %s\n", CAChannelLayouts::ConstantToString(mFileChannelLayout.Tag())); -#endif - } - mMode = kPreparingToCreate; - FileFormatChanged(&parentDir, filename, filetype); -} - -// _______________________________________________________________________________________ -// -// called to create the file -- or update its format/channel layout/properties based on an encoder -// setting change -void CAAudioFile::FileFormatChanged(const FSRef *parentDir, CFStringRef filename, AudioFileTypeID filetype) -{ - LOG_FUNCTION("CAAudioFile::FileFormatChanged", "%p", this); - XThrowIf(mMode != kPreparingToCreate && mMode != kPreparingToWrite, kExtAudioFileError_InvalidOperationOrder, "new file not prepared"); - - UInt32 propertySize; - OSStatus err; - AudioStreamBasicDescription saveFileDataFormat = mFileDataFormat; - -#if VERBOSE_CONVERTER - mFileDataFormat.PrintFormat(stdout, "", "Specified file data format"); -#endif - - // Find out the actual format the converter will produce. This is necessary in - // case the bitrate has forced a lower sample rate, which needs to be set correctly - // in the stream description passed to AudioFileCreate. - if (mConverter != NULL) { - propertySize = sizeof(AudioStreamBasicDescription); - Float64 origSampleRate = mFileDataFormat.mSampleRate; - XThrowIfError(AudioConverterGetProperty(mConverter, kAudioConverterCurrentOutputStreamDescription, &propertySize, &mFileDataFormat), "get audio converter's output stream description"); - // do the same for the channel layout being output by the converter -#if VERBOSE_CONVERTER - mFileDataFormat.PrintFormat(stdout, "", "Converter output"); -#endif - if (fiszero(mFileDataFormat.mSampleRate)) - mFileDataFormat.mSampleRate = origSampleRate; - err = AudioConverterGetPropertyInfo(mConverter, kAudioConverterOutputChannelLayout, &propertySize, NULL); - if (err == noErr && propertySize > 0) { - AudioChannelLayout *layout = static_cast<AudioChannelLayout *>(malloc(propertySize)); - err = AudioConverterGetProperty(mConverter, kAudioConverterOutputChannelLayout, &propertySize, layout); - if (err) { - free(layout); - XThrow(err, "couldn't get audio converter's output channel layout"); - } - mFileChannelLayout = layout; -#if VERBOSE_CHANNELMAP - printf("got new file's channel layout from converter: %s\n", CAChannelLayouts::ConstantToString(mFileChannelLayout.Tag())); -#endif - free(layout); - } - } - - // create the output file - if (mMode == kPreparingToCreate) { - CAStreamBasicDescription newFileDataFormat = mFileDataFormat; - if (fiszero(newFileDataFormat.mSampleRate)) - newFileDataFormat.mSampleRate = 44100; // just make something up for now -#if VERBOSE_CONVERTER - newFileDataFormat.PrintFormat(stdout, "", "Applied to new file"); -#endif - XThrowIfError(AudioFileCreate(parentDir, filename, filetype, &newFileDataFormat, 0, &mFSRef, &mAudioFile), "create audio file"); - mMode = kPreparingToWrite; - mOwnOpenFile = true; - } else if (saveFileDataFormat != mFileDataFormat || fnotequal(saveFileDataFormat.mSampleRate, mFileDataFormat.mSampleRate)) { - // second check must be explicit since operator== on ASBD treats SR of zero as "don't care" - if (fiszero(mFileDataFormat.mSampleRate)) - mFileDataFormat.mSampleRate = mClientDataFormat.mSampleRate; -#if VERBOSE_CONVERTER - mFileDataFormat.PrintFormat(stdout, "", "Applied to new file"); -#endif - XThrowIf(fiszero(mFileDataFormat.mSampleRate), kExtAudioFileError_InvalidDataFormat, "file's sample rate is 0"); - XThrowIfError(AudioFileSetProperty(mAudioFile, kAudioFilePropertyDataFormat, sizeof(AudioStreamBasicDescription), &mFileDataFormat), "couldn't update file's data format"); - } - - UInt32 deferSizeUpdates = 1; - err = AudioFileSetProperty(mAudioFile, kAudioFilePropertyDeferSizeUpdates, sizeof(UInt32), &deferSizeUpdates); - - if (mConverter != NULL) { - // encoder - // get the magic cookie, if any, from the converter - delete[] mMagicCookie; mMagicCookie = NULL; - mMagicCookieSize = 0; - - err = AudioConverterGetPropertyInfo(mConverter, kAudioConverterCompressionMagicCookie, &propertySize, NULL); - - // we can get a noErr result and also a propertySize == 0 - // -- if the file format does support magic cookies, but this file doesn't have one. - if (err == noErr && propertySize > 0) { - mMagicCookie = new Byte[propertySize]; - XThrowIfError(AudioConverterGetProperty(mConverter, kAudioConverterCompressionMagicCookie, &propertySize, mMagicCookie), "get audio converter's magic cookie"); - mMagicCookieSize = propertySize; // the converter lies and tell us the wrong size - // now set the magic cookie on the output file - UInt32 willEatTheCookie = false; - // the converter wants to give us one; will the file take it? - err = AudioFileGetPropertyInfo(mAudioFile, kAudioFilePropertyMagicCookieData, - NULL, &willEatTheCookie); - if (err == noErr && willEatTheCookie) { -#if VERBOSE_CONVERTER - printf("Setting cookie on encoded file\n"); -#endif - XThrowIfError(AudioFileSetProperty(mAudioFile, kAudioFilePropertyMagicCookieData, mMagicCookieSize, mMagicCookie), "set audio file's magic cookie"); - } - } - - // get maximum packet size - propertySize = sizeof(UInt32); - XThrowIfError(AudioConverterGetProperty(mConverter, kAudioConverterPropertyMaximumOutputPacketSize, &propertySize, &mFileMaxPacketSize), "get audio converter's maximum output packet size"); - - AllocateBuffers(true /* okToFail */); - } else { - InitFileMaxPacketSize(); - } - - if (mFileChannelLayout.IsValid() && mFileChannelLayout.NumberChannels() > 2) { - // don't bother tagging mono/stereo files - UInt32 isWritable; - err = AudioFileGetPropertyInfo(mAudioFile, kAudioFilePropertyChannelLayout, NULL, &isWritable); - if (!err && isWritable) { -#if VERBOSE_CHANNELMAP - printf("writing file's channel layout: %s\n", CAChannelLayouts::ConstantToString(mFileChannelLayout.Tag())); -#endif - err = AudioFileSetProperty(mAudioFile, kAudioFilePropertyChannelLayout, - mFileChannelLayout.Size(), &mFileChannelLayout.Layout()); - if (err) - CAXException::Warning("could not set the file's channel layout", err); - } else { -#if VERBOSE_CHANNELMAP - printf("file won't accept a channel layout (write)\n"); -#endif - } - } - - UpdateClientMaxPacketSize(); // also sets mFrame0Offset - mPacketMark = 0; - mFrameMark = 0; -} - -// _______________________________________________________________________________________ -// -void CAAudioFile::InitFileMaxPacketSize() -{ - LOG_FUNCTION("CAAudioFile::InitFileMaxPacketSize", "%p", this); - UInt32 propertySize = sizeof(UInt32); - OSStatus err = AudioFileGetProperty(mAudioFile, kAudioFilePropertyMaximumPacketSize, - &propertySize, &mFileMaxPacketSize); - if (err) { - // workaround for 3361377: not all file formats' maximum packet sizes are supported - if (!mFileDataFormat.IsPCM()) - XThrowIfError(err, "get audio file's maximum packet size"); - mFileMaxPacketSize = mFileDataFormat.mBytesPerFrame; - } - AllocateBuffers(true /* okToFail */); -} - - -// _______________________________________________________________________________________ -// -SInt64 CAAudioFile::FileDataOffset() -{ - if (mFileDataOffset < 0) { - UInt32 propertySize = sizeof(SInt64); - XThrowIfError(AudioFileGetProperty(mAudioFile, kAudioFilePropertyDataOffset, &propertySize, &mFileDataOffset), "couldn't get file's data offset"); - } - return mFileDataOffset; -} - -// _______________________________________________________________________________________ -// -SInt64 CAAudioFile::GetNumberFrames() const -{ - AudioFilePacketTableInfo pti; - UInt32 propertySize = sizeof(pti); - OSStatus err = AudioFileGetProperty(mAudioFile, kAudioFilePropertyPacketTableInfo, &propertySize, &pti); - if (err == noErr) - return pti.mNumberValidFrames; - return mFileDataFormat.mFramesPerPacket * GetNumberPackets() - mFrame0Offset; -} - -// _______________________________________________________________________________________ -// -void CAAudioFile::SetNumberFrames(SInt64 nFrames) -{ - XThrowIf(mFileDataFormat.mFramesPerPacket != 1, kExtAudioFileError_InvalidDataFormat, "SetNumberFrames only supported for PCM"); - XThrowIfError(AudioFileSetProperty(mAudioFile, kAudioFilePropertyAudioDataPacketCount, sizeof(SInt64), &nFrames), "Couldn't set number of packets on audio file"); -} - -// _______________________________________________________________________________________ -// -// call for existing file, NOT new one - from Open() or Wrap() -void CAAudioFile::GetExistingFileInfo() -{ - LOG_FUNCTION("CAAudioFile::GetExistingFileInfo", "%p", this); - UInt32 propertySize; - OSStatus err; - - // get mFileDataFormat - propertySize = sizeof(AudioStreamBasicDescription); - XThrowIfError(AudioFileGetProperty(mAudioFile, kAudioFilePropertyDataFormat, &propertySize, &mFileDataFormat), "get audio file's data format"); - - // get mFileChannelLayout - err = AudioFileGetPropertyInfo(mAudioFile, kAudioFilePropertyChannelLayout, &propertySize, NULL); - if (err == noErr && propertySize > 0) { - AudioChannelLayout *layout = static_cast<AudioChannelLayout *>(malloc(propertySize)); - err = AudioFileGetProperty(mAudioFile, kAudioFilePropertyChannelLayout, &propertySize, layout); - if (err == noErr) { - mFileChannelLayout = layout; -#if VERBOSE_CHANNELMAP - printf("existing file's channel layout: %s\n", CAChannelLayouts::ConstantToString(mFileChannelLayout.Tag())); -#endif - } - free(layout); - XThrowIfError(err, "get audio file's channel layout"); - } - if (mMode != kReading) - return; - -#if 0 - // get mNumberPackets - propertySize = sizeof(mNumberPackets); - XThrowIfError(AudioFileGetProperty(mAudioFile, kAudioFilePropertyAudioDataPacketCount, &propertySize, &mNumberPackets), "get audio file's packet count"); -#if VERBOSE_IO - printf("CAAudioFile::GetExistingFileInfo: %qd packets\n", mNumberPackets); -#endif -#endif - - // get mMagicCookie - err = AudioFileGetPropertyInfo(mAudioFile, kAudioFilePropertyMagicCookieData, &propertySize, NULL); - if (err == noErr && propertySize > 0) { - mMagicCookie = new Byte[propertySize]; - mMagicCookieSize = propertySize; - XThrowIfError(AudioFileGetProperty(mAudioFile, kAudioFilePropertyMagicCookieData, &propertySize, mMagicCookie), "get audio file's magic cookie"); - } - InitFileMaxPacketSize(); - mPacketMark = 0; - mFrameMark = 0; - - UpdateClientMaxPacketSize(); -} - -// ======================================================================================= - -// _______________________________________________________________________________________ -// -void CAAudioFile::SetFileChannelLayout(const CAAudioChannelLayout &layout) -{ - LOG_FUNCTION("CAAudioFile::SetFileChannelLayout", "%p", this); - mFileChannelLayout = layout; -#if VERBOSE_CHANNELMAP - printf("file channel layout set explicitly (%s): %s\n", mMode == kReading ? "read" : "write", CAChannelLayouts::ConstantToString(mFileChannelLayout.Tag())); -#endif - if (mMode != kReading) - FileFormatChanged(); -} - -// _______________________________________________________________________________________ -// -void CAAudioFile::SetClientFormat(const CAStreamBasicDescription &dataFormat, const CAAudioChannelLayout *layout) -{ - LOG_FUNCTION("CAAudioFile::SetClientFormat", "%p", this); - XThrowIf(!dataFormat.IsPCM(), kExtAudioFileError_NonPCMClientFormat, "non-PCM client format on audio file"); - - bool dataFormatChanging = (mClientDataFormat.mFormatID == 0 || mClientDataFormat != dataFormat); - - if (dataFormatChanging) { - CloseConverter(); - if (mWriteBufferList) { - delete mWriteBufferList; - mWriteBufferList = NULL; - } - mClientDataFormat = dataFormat; - } - - if (layout && layout->IsValid()) { - XThrowIf(layout->NumberChannels() != mClientDataFormat.NumberChannels(), kExtAudioFileError_InvalidChannelMap, "inappropriate channel map"); - mClientChannelLayout = *layout; - } - - bool differentLayouts; - if (mClientChannelLayout.IsValid()) { - if (mFileChannelLayout.IsValid()) { - differentLayouts = mClientChannelLayout.Tag() != mFileChannelLayout.Tag(); -#if VERBOSE_CHANNELMAP - printf("two valid layouts, %s\n", differentLayouts ? "different" : "same"); -#endif - } else { - differentLayouts = false; -#if VERBOSE_CHANNELMAP - printf("valid client layout, unknown file layout\n"); -#endif - } - } else { - differentLayouts = false; -#if VERBOSE_CHANNELMAP - if (mFileChannelLayout.IsValid()) - printf("valid file layout, unknown client layout\n"); - else - printf("two invalid layouts\n"); -#endif - } - - if (mClientDataFormat != mFileDataFormat || differentLayouts) { - // We need an AudioConverter. - if (mMode == kReading) { - // file -> client (decode) -//mFileDataFormat.PrintFormat( stdout, "", "File: "); -//mClientDataFormat.PrintFormat(stdout, "", "Client: "); - - if (mConverter == NULL) - XThrowIfError(AudioConverterNew(&mFileDataFormat, &mClientDataFormat, &mConverter), - "create audio converter"); - -#if VERBOSE_CONVERTER - printf("CAAudioFile %p -- created converter\n", this); - CAShow(mConverter); -#endif - // set the magic cookie, if any (for decode) - if (mMagicCookie) - SetConverterProperty(kAudioConverterDecompressionMagicCookie, mMagicCookieSize, mMagicCookie, mFileDataFormat.IsPCM()); - // we get cookies from some AIFF's but the converter barfs on them, - // so we set canFail to true for PCM - - SetConverterChannelLayout(false, mFileChannelLayout); - SetConverterChannelLayout(true, mClientChannelLayout); - - // propagate leading/trailing frame counts - if (mFileDataFormat.mBitsPerChannel == 0) { - UInt32 propertySize; - OSStatus err; - AudioFilePacketTableInfo pti; - propertySize = sizeof(pti); - err = AudioFileGetProperty(mAudioFile, kAudioFilePropertyPacketTableInfo, &propertySize, &pti); - if (err == noErr && (pti.mPrimingFrames > 0 || pti.mRemainderFrames > 0)) { - AudioConverterPrimeInfo primeInfo; - primeInfo.leadingFrames = pti.mPrimingFrames; - primeInfo.trailingFrames = pti.mRemainderFrames; - /* ignore any error. better to play it at all than not. */ - /*err = */AudioConverterSetProperty(mConverter, kAudioConverterPrimeInfo, sizeof(primeInfo), &primeInfo); - //XThrowIfError(err, "couldn't set prime info on converter"); - } - } - } else if (mMode == kPreparingToCreate || mMode == kPreparingToWrite) { - // client -> file (encode) - if (mConverter == NULL) - XThrowIfError(AudioConverterNew(&mClientDataFormat, &mFileDataFormat, &mConverter), "create audio converter"); - mWriteBufferList = CABufferList::New("", mClientDataFormat); - SetConverterChannelLayout(false, mClientChannelLayout); - SetConverterChannelLayout(true, mFileChannelLayout); - if (mMode == kPreparingToWrite) - FileFormatChanged(); - } else - XThrowIfError(kExtAudioFileError_InvalidOperationOrder, "audio file format not yet known"); - } - UpdateClientMaxPacketSize(); -} - -// _______________________________________________________________________________________ -// -OSStatus CAAudioFile::SetConverterProperty( - AudioConverterPropertyID inPropertyID, - UInt32 inPropertyDataSize, - const void* inPropertyData, - bool inCanFail) -{ - OSStatus err = noErr; - //LOG_FUNCTION("ExtAudioFile::SetConverterProperty", "%p %-4.4s", this, (char *)&inPropertyID); - if (inPropertyID == kAudioConverterPropertySettings && *(CFPropertyListRef *)inPropertyData == NULL) - ; - else { - err = AudioConverterSetProperty(mConverter, inPropertyID, inPropertyDataSize, inPropertyData); - if (!inCanFail) { - XThrowIfError(err, "set audio converter property"); - } - } - UpdateClientMaxPacketSize(); - if (mMode == kPreparingToWrite) - FileFormatChanged(); - return err; -} - -// _______________________________________________________________________________________ -// -void CAAudioFile::SetConverterChannelLayout(bool output, const CAAudioChannelLayout &layout) -{ - LOG_FUNCTION("CAAudioFile::SetConverterChannelLayout", "%p", this); - OSStatus err; - - if (layout.IsValid()) { -#if VERBOSE_CHANNELMAP - printf("Setting converter's %s channel layout: %s\n", output ? "output" : "input", - CAChannelLayouts::ConstantToString(mFileChannelLayout.Tag())); -#endif - if (output) { - err = AudioConverterSetProperty(mConverter, kAudioConverterOutputChannelLayout, - layout.Size(), &layout.Layout()); - XThrowIf(err && err != kAudioConverterErr_OperationNotSupported, err, "couldn't set converter's output channel layout"); - } else { - err = AudioConverterSetProperty(mConverter, kAudioConverterInputChannelLayout, - layout.Size(), &layout.Layout()); - XThrowIf(err && err != kAudioConverterErr_OperationNotSupported, err, "couldn't set converter's input channel layout"); - } - if (mMode == kPreparingToWrite) - FileFormatChanged(); - } -} - -// _______________________________________________________________________________________ -// -CFArrayRef CAAudioFile::GetConverterConfig() -{ - CFArrayRef plist; - UInt32 propertySize = sizeof(plist); - XThrowIfError(AudioConverterGetProperty(mConverter, kAudioConverterPropertySettings, &propertySize, &plist), "get converter property settings"); - return plist; -} - -// _______________________________________________________________________________________ -// -void CAAudioFile::UpdateClientMaxPacketSize() -{ - LOG_FUNCTION("CAAudioFile::UpdateClientMaxPacketSize", "%p", this); - mFrame0Offset = 0; - if (mConverter != NULL) { - AudioConverterPropertyID property = (mMode == kReading) ? - kAudioConverterPropertyMaximumOutputPacketSize : - kAudioConverterPropertyMaximumInputPacketSize; - - UInt32 propertySize = sizeof(UInt32); - XThrowIfError(AudioConverterGetProperty(mConverter, property, &propertySize, &mClientMaxPacketSize), - "get audio converter's maximum packet size"); - - if (mFileDataFormat.mBitsPerChannel == 0) { - AudioConverterPrimeInfo primeInfo; - propertySize = sizeof(primeInfo); - OSStatus err = AudioConverterGetProperty(mConverter, kAudioConverterPrimeInfo, &propertySize, &primeInfo); - if (err == noErr) - mFrame0Offset = primeInfo.leadingFrames; -#if VERBOSE_CONVERTER - printf("kAudioConverterPrimeInfo: err = %ld, leadingFrames = %ld\n", err, mFrame0Offset); -#endif - } - } else { - mClientMaxPacketSize = mFileMaxPacketSize; - } -} - -// _______________________________________________________________________________________ -// Allocates: mIOBufferList, mIOBufferSizePackets, mPacketDescs -// Dependent on: mFileMaxPacketSize, mIOBufferSizeBytes -void CAAudioFile::AllocateBuffers(bool okToFail) -{ - LOG_FUNCTION("CAAudioFile::AllocateBuffers", "%p", this); - if (mFileMaxPacketSize == 0) { - if (okToFail) - return; - XThrowIf(true, kExtAudioFileError_MaxPacketSizeUnknown, "file's maximum packet size is 0"); - } - UInt32 bufferSizeBytes = mIOBufferSizeBytes = std::max(mIOBufferSizeBytes, mFileMaxPacketSize); - // must be big enough for at least one maximum size packet - - if (mIOBufferList.mBuffers[0].mDataByteSize != bufferSizeBytes) { - mIOBufferList.mNumberBuffers = 1; - mIOBufferList.mBuffers[0].mNumberChannels = mFileDataFormat.mChannelsPerFrame; - if (!mClientOwnsIOBuffer) { - //printf("reallocating I/O buffer\n"); - delete[] (Byte *)mIOBufferList.mBuffers[0].mData; - mIOBufferList.mBuffers[0].mData = new Byte[bufferSizeBytes]; - } - mIOBufferList.mBuffers[0].mDataByteSize = bufferSizeBytes; - mIOBufferSizePackets = bufferSizeBytes / mFileMaxPacketSize; - } - - UInt32 propertySize = sizeof(UInt32); - UInt32 externallyFramed; - XThrowIfError(AudioFormatGetProperty(kAudioFormatProperty_FormatIsExternallyFramed, - sizeof(AudioStreamBasicDescription), &mFileDataFormat, &propertySize, &externallyFramed), - "is format externally framed"); - if (mNumPacketDescs != (externallyFramed ? mIOBufferSizePackets : 0)) { - delete[] mPacketDescs; - mPacketDescs = NULL; - mNumPacketDescs = 0; - - if (externallyFramed) { - //printf("reallocating packet descs\n"); - mPacketDescs = new AudioStreamPacketDescription[mIOBufferSizePackets]; - mNumPacketDescs = mIOBufferSizePackets; - } - } -} - -// _______________________________________________________________________________________ -// -void CAAudioFile::SetIOBuffer(void *buf) -{ - if (!mClientOwnsIOBuffer) - delete[] (Byte *)mIOBufferList.mBuffers[0].mData; - mIOBufferList.mBuffers[0].mData = buf; - - if (buf == NULL) { - mClientOwnsIOBuffer = false; - SetIOBufferSizeBytes(mIOBufferSizeBytes); - } else { - mClientOwnsIOBuffer = true; - AllocateBuffers(); - } -// printf("CAAudioFile::SetIOBuffer %p: %p, 0x%lx bytes, mClientOwns = %d\n", this, mIOBufferList.mBuffers[0].mData, mIOBufferSizeBytes, mClientOwnsIOBuffer); -} - -// =============================================================================== - -/* -For Tiger: -added kAudioFilePropertyPacketToFrame and kAudioFilePropertyFrameToPacket. -You pass in an AudioFramePacketTranslation struct, with the appropriate field filled in, to AudioFileGetProperty. - - kAudioFilePropertyPacketToFrame = 'pkfr', - // pass a AudioFramePacketTranslation with mPacket filled out and get mFrame back. mFrameOffsetInPacket is ignored. - kAudioFilePropertyFrameToPacket = 'frpk', - // pass a AudioFramePacketTranslation with mFrame filled out and get mPacket and mFrameOffsetInPacket back. - -struct AudioFramePacketTranslation -{ - SInt64 mFrame; - SInt64 mPacket; - UInt32 mFrameOffsetInPacket; -}; -*/ - -SInt64 CAAudioFile::PacketToFrame(SInt64 packet) const -{ - AudioFramePacketTranslation trans; - UInt32 propertySize; - - switch (mFileDataFormat.mFramesPerPacket) { - case 1: - return packet; - case 0: - trans.mPacket = packet; - propertySize = sizeof(trans); - XThrowIfError(AudioFileGetProperty(mAudioFile, kAudioFilePropertyPacketToFrame, &propertySize, &trans), - "packet <-> frame translation unimplemented for format with variable frames/packet"); - return trans.mFrame; - } - return packet * mFileDataFormat.mFramesPerPacket; -} - -SInt64 CAAudioFile::FrameToPacket(SInt64 inFrame) const -{ - AudioFramePacketTranslation trans; - UInt32 propertySize; - - switch (mFileDataFormat.mFramesPerPacket) { - case 1: - return inFrame; - case 0: - trans.mFrame = inFrame; - propertySize = sizeof(trans); - XThrowIfError(AudioFileGetProperty(mAudioFile, kAudioFilePropertyFrameToPacket, &propertySize, &trans), - "packet <-> frame translation unimplemented for format with variable frames/packet"); - return trans.mPacket; - } - return inFrame / mFileDataFormat.mFramesPerPacket; -} - -// _______________________________________________________________________________________ -// - -SInt64 CAAudioFile::Tell() const // frameNumber -{ - return mFrameMark - mFrame0Offset; -} - -void CAAudioFile::SeekToPacket(SInt64 packetNumber) -{ -#if VERBOSE_IO - printf("CAAudioFile::SeekToPacket: %qd\n", packetNumber); -#endif - XThrowIf(mMode != kReading || packetNumber < 0 /*|| packetNumber >= mNumberPackets*/ , kExtAudioFileError_InvalidSeek, "seek to packet in audio file"); - if (mPacketMark == packetNumber) - return; // already there! don't reset converter - mPacketMark = packetNumber; - - mFrameMark = PacketToFrame(packetNumber) - mFrame0Offset; - mFramesToSkipFollowingSeek = 0; - if (mConverter) - // must reset -- if we reached end of stream. converter will no longer work otherwise - AudioConverterReset(mConverter); -} - -/* - Example: AAC, 1024 frames/packet, 2112 frame offset - - 2112 - | - Absolute frames: 0 1024 2048 | 3072 - +---------+---------+--|------+---------+---------+ - Packets: | 0 | 1 | | 2 | 3 | 4 | - +---------+---------+--|------+---------+---------+ - Client frames: -2112 -1088 -64 | 960 SeekToFrame, TellFrame - | - 0 - - * Offset between absolute and client frames is mFrame0Offset. - *** mFrameMark is in client frames *** - - Examples: - clientFrame 0 960 1000 1024 - absoluteFrame 2112 3072 3112 3136 - packet 0 0 0 1 - tempFrameMark* -2112 -2112 -2112 -1088 - mFramesToSkipFollowingSeek 2112 3072 3112 2112 -*/ -void CAAudioFile::Seek(SInt64 clientFrame) -{ - if (clientFrame == mFrameMark) - return; // already there! don't reset converter - - //SInt64 absoluteFrame = clientFrame + mFrame0Offset; - XThrowIf(mMode != kReading || clientFrame < 0 || !mClientDataFormat.IsPCM(), kExtAudioFileError_InvalidSeek, "seek to frame in audio file"); - -#if VERBOSE_IO - SInt64 prevFrameMark = mFrameMark; -#endif - - SInt64 packet; - packet = FrameToPacket(clientFrame); - if (packet < 0) - packet = 0; - SeekToPacket(packet); - // this will have backed up mFrameMark to match the beginning of the packet - mFramesToSkipFollowingSeek = std::max(UInt32(clientFrame - mFrameMark), UInt32(0)); - mFrameMark = clientFrame; - -#if VERBOSE_IO - printf("CAAudioFile::SeekToFrame: frame %qd (from %qd), packet %qd, skip %ld frames\n", mFrameMark, prevFrameMark, packet, mFramesToSkipFollowingSeek); -#endif -} - -// _______________________________________________________________________________________ -// -void CAAudioFile::Read(UInt32 &ioNumPackets, AudioBufferList *ioData) - // May read fewer packets than requested if: - // buffer is not big enough - // file does not contain that many more packets - // Note that eofErr is not fatal, just results in 0 packets returned - // ioData's buffer sizes may be shortened -{ - XThrowIf(mClientMaxPacketSize == 0, kExtAudioFileError_MaxPacketSizeUnknown, "client maximum packet size is 0"); - if (mIOBufferList.mBuffers[0].mData == NULL) { -#if DEBUG - printf("warning: CAAudioFile::AllocateBuffers called from ReadPackets\n"); -#endif - AllocateBuffers(); - } - UInt32 bufferSizeBytes = ioData->mBuffers[0].mDataByteSize; - UInt32 maxNumPackets = bufferSizeBytes / mClientMaxPacketSize; - // older versions of AudioConverterFillComplexBuffer don't do this, so do our own sanity check - UInt32 nPackets = std::min(ioNumPackets, maxNumPackets); - - mMaxPacketsToRead = ~0UL; - - if (mClientDataFormat.mFramesPerPacket == 1) { // PCM or equivalent - while (mFramesToSkipFollowingSeek > 0) { - UInt32 skipFrames = std::min(mFramesToSkipFollowingSeek, maxNumPackets); - UInt32 framesPerPacket; - if ((framesPerPacket=mFileDataFormat.mFramesPerPacket) > 0) - mMaxPacketsToRead = (skipFrames + framesPerPacket - 1) / framesPerPacket; - - if (mConverter == NULL) { - XThrowIfError(ReadInputProc(NULL, &skipFrames, ioData, NULL, this), "read audio file"); - } else { -#if CAAUDIOFILE_PROFILE - mInConverter = true; -#endif - StartTiming(this, fill); - XThrowIfError(AudioConverterFillComplexBuffer(mConverter, ReadInputProc, this, &skipFrames, ioData, NULL), "convert audio packets (pcm read)"); - ElapsedTime(this, fill, mTicksInConverter); -#if CAAUDIOFILE_PROFILE - mInConverter = false; -#endif - } - if (skipFrames == 0) { // hit EOF - ioNumPackets = 0; - return; - } - mFrameMark += skipFrames; -#if VERBOSE_IO - printf("CAAudioFile::ReadPackets: skipped %ld frames\n", skipFrames); -#endif - - mFramesToSkipFollowingSeek -= skipFrames; - - // restore mDataByteSize - for (int i = ioData->mNumberBuffers; --i >= 0 ; ) - ioData->mBuffers[i].mDataByteSize = bufferSizeBytes; - } - } - - if (mFileDataFormat.mFramesPerPacket > 0) - // don't read more packets than we are being asked to produce - mMaxPacketsToRead = nPackets / mFileDataFormat.mFramesPerPacket + 1; - if (mConverter == NULL) { - XThrowIfError(ReadInputProc(NULL, &nPackets, ioData, NULL, this), "read audio file"); - } else { -#if CAAUDIOFILE_PROFILE - mInConverter = true; -#endif - StartTiming(this, fill); - XThrowIfError(AudioConverterFillComplexBuffer(mConverter, ReadInputProc, this, &nPackets, ioData, NULL), "convert audio packets (read)"); - ElapsedTime(this, fill, mTicksInConverter); -#if CAAUDIOFILE_PROFILE - mInConverter = false; -#endif - } - if (mClientDataFormat.mFramesPerPacket == 1) - mFrameMark += nPackets; - - ioNumPackets = nPackets; -} - -// _______________________________________________________________________________________ -// -OSStatus CAAudioFile::ReadInputProc( AudioConverterRef inAudioConverter, - UInt32* ioNumberDataPackets, - AudioBufferList* ioData, - AudioStreamPacketDescription** outDataPacketDescription, - void* inUserData) -{ - CAAudioFile *This = static_cast<CAAudioFile *>(inUserData); - -#if 0 - SInt64 remainingPacketsInFile = This->mNumberPackets - This->mPacketMark; - if (remainingPacketsInFile <= 0) { - *ioNumberDataPackets = 0; - ioData->mBuffers[0].mDataByteSize = 0; - if (outDataPacketDescription) - *outDataPacketDescription = This->mPacketDescs; -#if VERBOSE_IO - printf("CAAudioFile::ReadInputProc: EOF\n"); -#endif - return noErr; // not eofErr; EOF is signified by 0 packets/0 bytes - } -#endif - - // determine how much to read - AudioBufferList *readBuffer; - UInt32 readPackets; - if (inAudioConverter != NULL) { - // getting called from converter, need to use our I/O buffer - readBuffer = &This->mIOBufferList; - readPackets = This->mIOBufferSizePackets; - } else { - // getting called directly from ReadPackets, use supplied buffer - if (This->mFileMaxPacketSize == 0) - return kExtAudioFileError_MaxPacketSizeUnknown; - readBuffer = ioData; - readPackets = std::min(*ioNumberDataPackets, readBuffer->mBuffers[0].mDataByteSize / This->mFileMaxPacketSize); - // don't attempt to read more packets than will fit in the buffer - } - // don't try to read past EOF -// if (readPackets > remainingPacketsInFile) -// readPackets = remainingPacketsInFile; - // don't read more packets than necessary to produce the requested amount of converted data - if (readPackets > This->mMaxPacketsToRead) { -#if VERBOSE_IO - printf("CAAudioFile::ReadInputProc: limiting read to %ld packets (from %ld)\n", This->mMaxPacketsToRead, readPackets); -#endif - readPackets = This->mMaxPacketsToRead; - } - - // read - UInt32 bytesRead; - OSStatus err; - - StartTiming(This, read); - StartTiming(This, readinconv); - err = AudioFileReadPackets(This->mAudioFile, This->mUseCache, &bytesRead, This->mPacketDescs, This->mPacketMark, &readPackets, readBuffer->mBuffers[0].mData); -#if CAAUDIOFILE_PROFILE - if (This->mInConverter) ElapsedTime(This, readinconv, This->mTicksInReadInConverter); -#endif - ElapsedTime(This, read, This->mTicksInIO); - - if (err) { - DebugMessageN1("Error %ld from AudioFileReadPackets!!!\n", err); - return err; - } - -#if VERBOSE_IO - printf("CAAudioFile::ReadInputProc: read %ld packets (%qd-%qd), %ld bytes, err %ld\n", readPackets, This->mPacketMark, This->mPacketMark + readPackets, bytesRead, err); -#if VERBOSE_IO >= 2 - if (This->mPacketDescs) { - for (UInt32 i = 0; i < readPackets; ++i) { - printf(" read packet %qd : offset %qd, length %ld\n", This->mPacketMark + i, This->mPacketDescs[i].mStartOffset, This->mPacketDescs[i].mDataByteSize); - } - } - printf(" read buffer:"); CAShowAudioBufferList(readBuffer, 0, 4); -#endif -#endif - if (readPackets == 0) { - *ioNumberDataPackets = 0; - ioData->mBuffers[0].mDataByteSize = 0; - return noErr; - } - - if (outDataPacketDescription) - *outDataPacketDescription = This->mPacketDescs; - ioData->mBuffers[0].mDataByteSize = bytesRead; - ioData->mBuffers[0].mData = readBuffer->mBuffers[0].mData; - - This->mPacketMark += readPackets; - if (This->mClientDataFormat.mFramesPerPacket != 1) { // for PCM client formats we update in Read - // but for non-PCM client format (weird case) we must update here/now - if (This->mFileDataFormat.mFramesPerPacket > 0) - This->mFrameMark += readPackets * This->mFileDataFormat.mFramesPerPacket; - else { - for (UInt32 i = 0; i < readPackets; ++i) - This->mFrameMark += This->mPacketDescs[i].mVariableFramesInPacket; - } - } - *ioNumberDataPackets = readPackets; - return noErr; -} - -// _______________________________________________________________________________________ -// -void CAAudioFile::Write(UInt32 numPackets, const AudioBufferList *data) -{ - if (mIOBufferList.mBuffers[0].mData == NULL) { -#if DEBUG - printf("warning: CAAudioFile::AllocateBuffers called from WritePackets\n"); -#endif - AllocateBuffers(); - } - - if (mMode == kPreparingToWrite) - mMode = kWriting; - else - XThrowIf(mMode != kWriting, kExtAudioFileError_InvalidOperationOrder, "can't write to this file"); - if (mConverter != NULL) { - mWritePackets = numPackets; - mWriteBufferList->SetFrom(data); - WritePacketsFromCallback(WriteInputProc, this); - } else { - StartTiming(this, write); - XThrowIfError(AudioFileWritePackets(mAudioFile, mUseCache, data->mBuffers[0].mDataByteSize, - NULL, mPacketMark, &numPackets, data->mBuffers[0].mData), - "write audio file"); - ElapsedTime(this, write, mTicksInIO); -#if VERBOSE_IO - printf("CAAudioFile::WritePackets: wrote %ld packets at %qd, %ld bytes\n", numPackets, mPacketMark, data->mBuffers[0].mDataByteSize); -#endif - //mNumberPackets = - mPacketMark += numPackets; - if (mFileDataFormat.mFramesPerPacket > 0) - mFrameMark += numPackets * mFileDataFormat.mFramesPerPacket; - // else: shouldn't happen since we're only called when there's no converter - } -} - -// _______________________________________________________________________________________ -// -void CAAudioFile::FlushEncoder() -{ - if (mConverter != NULL) { - mFinishingEncoding = true; - WritePacketsFromCallback(WriteInputProc, this); - mFinishingEncoding = false; - - // get priming info from converter, set it on the file - if (mFileDataFormat.mBitsPerChannel == 0) { - UInt32 propertySize; - OSStatus err; - AudioConverterPrimeInfo primeInfo; - propertySize = sizeof(primeInfo); - - err = AudioConverterGetProperty(mConverter, kAudioConverterPrimeInfo, &propertySize, &primeInfo); - if (err == noErr) { - AudioFilePacketTableInfo pti; - propertySize = sizeof(pti); - err = AudioFileGetProperty(mAudioFile, kAudioFilePropertyPacketTableInfo, &propertySize, &pti); - if (err == noErr) { -//printf("old packet table info: %qd valid, %ld priming, %ld remainder\n", pti.mNumberValidFrames, pti.mPrimingFrames, pti.mRemainderFrames); - UInt64 totalFrames = pti.mNumberValidFrames + pti.mPrimingFrames + pti.mRemainderFrames; - pti.mPrimingFrames = primeInfo.leadingFrames; - pti.mRemainderFrames = primeInfo.trailingFrames; - pti.mNumberValidFrames = totalFrames - pti.mPrimingFrames - pti.mRemainderFrames; -//printf("new packet table info: %qd valid, %ld priming, %ld remainder\n", pti.mNumberValidFrames, pti.mPrimingFrames, pti.mRemainderFrames); - XThrowIfError(AudioFileSetProperty(mAudioFile, kAudioFilePropertyPacketTableInfo, sizeof(pti), &pti), "couldn't set packet table info on audio file"); - } - } - } - } -} - -// _______________________________________________________________________________________ -// -OSStatus CAAudioFile::WriteInputProc( AudioConverterRef /*inAudioConverter*/, - UInt32 * ioNumberDataPackets, - AudioBufferList* ioData, - AudioStreamPacketDescription ** outDataPacketDescription, - void* inUserData) -{ - CAAudioFile *This = static_cast<CAAudioFile *>(inUserData); - if (This->mFinishingEncoding) { - *ioNumberDataPackets = 0; - ioData->mBuffers[0].mDataByteSize = 0; - ioData->mBuffers[0].mData = NULL; - if (outDataPacketDescription) - *outDataPacketDescription = NULL; - return noErr; - } - UInt32 numPackets = This->mWritePackets; - if (numPackets == 0) { - return kNoMoreInputRightNow; - } - This->mWriteBufferList->ToAudioBufferList(ioData); - This->mWriteBufferList->BytesConsumed(numPackets * This->mClientDataFormat.mBytesPerFrame); - *ioNumberDataPackets = numPackets; - if (outDataPacketDescription) - *outDataPacketDescription = NULL; - This->mWritePackets -= numPackets; - return noErr; -} - -// _______________________________________________________________________________________ -// -#if VERBOSE_IO -static void hexdump(const void *addr, long len) -{ - const Byte *p = (Byte *)addr; - UInt32 offset = 0; - - if (len > 0x400) len = 0x400; - - while (len > 0) { - int n = len > 16 ? 16 : len; - printf("%08lX: ", offset); - for (int i = 0; i < 16; ++i) - if (i < n) - printf("%02X ", p[i]); - else printf(" "); - for (int i = 0; i < 16; ++i) - if (i < n) - putchar(p[i] >= ' ' && p[i] < 127 ? p[i] : '.'); - else putchar(' '); - putchar('\n'); - p += 16; - len -= 16; - offset += 16; - } -} -#endif - -// _______________________________________________________________________________________ -// -void CAAudioFile::WritePacketsFromCallback( - AudioConverterComplexInputDataProc inInputDataProc, - void * inInputDataProcUserData) -{ - while (true) { - // keep writing until we exhaust the input (temporary stop), or produce no output (EOF) - UInt32 numEncodedPackets = mIOBufferSizePackets; - mIOBufferList.mBuffers[0].mDataByteSize = mIOBufferSizeBytes; -#if CAAUDIOFILE_PROFILE - mInConverter = true; -#endif - StartTiming(this, fill); - OSStatus err = AudioConverterFillComplexBuffer(mConverter, inInputDataProc, inInputDataProcUserData, - &numEncodedPackets, &mIOBufferList, mPacketDescs); - ElapsedTime(this, fill, mTicksInConverter); -#if CAAUDIOFILE_PROFILE - mInConverter = false; -#endif - XThrowIf(err != 0 && err != kNoMoreInputRightNow, err, "convert audio packets (write)"); - if (numEncodedPackets == 0) - break; - Byte *buf = (Byte *)mIOBufferList.mBuffers[0].mData; -#if VERBOSE_IO - printf("CAAudioFile::WritePacketsFromCallback: wrote %ld packets, %ld bytes\n", numEncodedPackets, mIOBufferList.mBuffers[0].mDataByteSize); - if (mPacketDescs) { - for (UInt32 i = 0; i < numEncodedPackets; ++i) { - printf(" write packet %qd : offset %qd, length %ld\n", mPacketMark + i, mPacketDescs[i].mStartOffset, mPacketDescs[i].mDataByteSize); -#if VERBOSE_IO >= 2 - hexdump(buf + mPacketDescs[i].mStartOffset, mPacketDescs[i].mDataByteSize); -#endif - } - } -#endif - StartTiming(this, write); - XThrowIfError(AudioFileWritePackets(mAudioFile, mUseCache, mIOBufferList.mBuffers[0].mDataByteSize, mPacketDescs, mPacketMark, &numEncodedPackets, buf), "write audio file"); - ElapsedTime(this, write, mTicksInIO); - mPacketMark += numEncodedPackets; - //mNumberPackets += numEncodedPackets; - if (mFileDataFormat.mFramesPerPacket > 0) - mFrameMark += numEncodedPackets * mFileDataFormat.mFramesPerPacket; - else { - for (UInt32 i = 0; i < numEncodedPackets; ++i) - mFrameMark += mPacketDescs[i].mVariableFramesInPacket; - } - if (err == kNoMoreInputRightNow) - break; - } -} - -#endif // !CAAF_USE_EXTAUDIOFILE |