diff options
Diffstat (limited to 'libs/appleutility/CoreAudio/AudioFile')
10 files changed, 5643 insertions, 0 deletions
diff --git a/libs/appleutility/CoreAudio/AudioFile/AFPublic/AudioFileComponentBase.cpp b/libs/appleutility/CoreAudio/AudioFile/AFPublic/AudioFileComponentBase.cpp new file mode 100644 index 0000000000..053da0a5d0 --- /dev/null +++ b/libs/appleutility/CoreAudio/AudioFile/AFPublic/AudioFileComponentBase.cpp @@ -0,0 +1,1040 @@ +/* + File: AudioFileComponentBase.cpp + Abstract: AudioFileComponentBase.h + Version: 1.1 + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple + 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 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. + + Copyright (C) 2014 Apple Inc. All Rights Reserved. + +*/ +#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__) + #include <AudioToolbox/AudioFileComponent.h> +#else + #include "AudioFileComponent.h" +#endif + +#include "AudioFileComponentBase.h" + +#if TARGET_OS_MAC + #if __LP64__ + // comp instance, parameters in forward order + #define PARAM(_typ, _name, _index, _nparams) \ + _typ _name = *(_typ *)¶ms->params[_index + 1]; + #else + // parameters in reverse order, then comp instance + #define PARAM(_typ, _name, _index, _nparams) \ + _typ _name = *(_typ *)¶ms->params[_nparams - 1 - _index]; + #endif +#elif TARGET_OS_WIN32 + // (no comp instance), parameters in forward order + #define PARAM(_typ, _name, _index, _nparams) \ + _typ _name = *(_typ *)¶ms->params[_index]; +#endif + +#define ACPI ((AudioComponentPlugInInstance *)self) +#define AFC ((AudioFileComponentBase *)&ACPI->mInstanceStorage) + +//---------------------------------------------------------------------------------------- + +static OSStatus CreateURL( + void * self, + CFURLRef inFileRef, + const AudioStreamBasicDescription *inFormat, + UInt32 inFlags) +{ + return AFC->AFAPI_CreateURL(inFileRef, inFormat, inFlags); +} + +static OSStatus OpenURL( + void * self, + CFURLRef inFileRef, + SInt8 inPermissions, + int inFileDescriptor) +{ + return AFC->AFAPI_OpenURL(inFileRef, inPermissions, inFileDescriptor); +} + +static OSStatus OpenWithCallbacks( + void * self, + void * inRefCon, + AudioFile_ReadProc inReadFunc, + AudioFile_WriteProc inWriteFunc, + AudioFile_GetSizeProc inGetSizeFunc, + AudioFile_SetSizeProc inSetSizeFunc) +{ + return AFC->AFAPI_OpenWithCallbacks(inRefCon, inReadFunc, inWriteFunc, inGetSizeFunc, inSetSizeFunc); +} + +static OSStatus InitializeWithCallbacks( + void * self, + void * inRefCon, + AudioFile_ReadProc inReadFunc, + AudioFile_WriteProc inWriteFunc, + AudioFile_GetSizeProc inGetSizeFunc, + AudioFile_SetSizeProc inSetSizeFunc, + UInt32 inFileType, + const AudioStreamBasicDescription *inFormat, + UInt32 inFlags) +{ + return AFC->AFAPI_InitializeWithCallbacks(inRefCon, inReadFunc, inWriteFunc, inGetSizeFunc, inSetSizeFunc, inFileType, inFormat, inFlags); +} + +static OSStatus Close( + void * self) +{ + return AFC->AFAPI_Close(); +} + +static OSStatus Optimize( + void * self) +{ + return AFC->AFAPI_Optimize(); +} + +static OSStatus ReadBytes( + void * self, + Boolean inUseCache, + SInt64 inStartingByte, + UInt32 *ioNumBytes, + void *outBuffer) +{ + return AFC->AFAPI_ReadBytes(inUseCache, inStartingByte, ioNumBytes, outBuffer); +} + + +static OSStatus WriteBytes( + void * self, + Boolean inUseCache, + SInt64 inStartingByte, + UInt32 *ioNumBytes, + const void *inBuffer) +{ + return AFC->AFAPI_WriteBytes(inUseCache, inStartingByte, ioNumBytes, inBuffer); +} + + +static OSStatus ReadPackets( + void * self, + Boolean inUseCache, + UInt32 *outNumBytes, + AudioStreamPacketDescription *outPacketDescriptions, + SInt64 inStartingPacket, + UInt32 *ioNumPackets, + void *outBuffer) +{ + return AFC->AFAPI_ReadPackets(inUseCache, outNumBytes, outPacketDescriptions, + inStartingPacket, ioNumPackets, outBuffer); +} + +static OSStatus ReadPacketData( + void * self, + Boolean inUseCache, + UInt32 *ioNumBytes, + AudioStreamPacketDescription *outPacketDescriptions, + SInt64 inStartingPacket, + UInt32 *ioNumPackets, + void *outBuffer) +{ + return AFC->AFAPI_ReadPacketData(inUseCache, ioNumBytes, outPacketDescriptions, + inStartingPacket, ioNumPackets, outBuffer); +} + +#if COREAUDIOTYPES_VERSION < 1050 +static OSStatus WritePackets( + void * self, + Boolean inUseCache, + UInt32 inNumBytes, + AudioStreamPacketDescription *inPacketDescriptions, + SInt64 inStartingPacket, + UInt32 *ioNumPackets, + const void *inBuffer) +#else +static OSStatus WritePackets( + void * self, + Boolean inUseCache, + UInt32 inNumBytes, + const AudioStreamPacketDescription *inPacketDescriptions, + SInt64 inStartingPacket, + UInt32 *ioNumPackets, + const void *inBuffer) +#endif +{ + return AFC->AFAPI_WritePackets(inUseCache, inNumBytes, + (const AudioStreamPacketDescription *)inPacketDescriptions, // this should be const (and is in 10.5 headers) + inStartingPacket, ioNumPackets, inBuffer); +} + +static OSStatus GetPropertyInfo( + void * self, + AudioFilePropertyID inPropertyID, + UInt32 *outDataSize, + UInt32 *isWritable) +{ + return AFC->AFAPI_GetPropertyInfo(inPropertyID, outDataSize, isWritable); +} + +static OSStatus GetProperty( + void * self, + AudioFilePropertyID inPropertyID, + UInt32 *ioDataSize, + void *ioData) +{ + return AFC->AFAPI_GetProperty(inPropertyID, ioDataSize, ioData); +} + + +static OSStatus SetProperty( + void * self, + AudioFilePropertyID inPropertyID, + UInt32 inDataSize, + const void *inData) +{ + return AFC->AFAPI_SetProperty(inPropertyID, inDataSize, inData); +} + +static OSStatus CountUserData( + void * self, + UInt32 inUserDataID, + UInt32 *outNumberItems) +{ + return AFC->AFAPI_CountUserData(inUserDataID, outNumberItems); +} + +static OSStatus GetUserDataSize( + void * self, + UInt32 inUserDataID, + UInt32 inIndex, + UInt32 *outDataSize) +{ + return AFC->AFAPI_GetUserDataSize(inUserDataID, inIndex, outDataSize); +} + +static OSStatus GetUserData( + void * self, + UInt32 inUserDataID, + UInt32 inIndex, + UInt32 *ioUserDataSize, + void *outUserData) +{ + return AFC->AFAPI_GetUserData(inUserDataID, inIndex, ioUserDataSize, outUserData); +} + +static OSStatus SetUserData( + void * self, + UInt32 inUserDataID, + UInt32 inIndex, + UInt32 inUserDataSize, + const void *inUserData) +{ + return AFC->AFAPI_SetUserData(inUserDataID, inIndex, inUserDataSize, inUserData); +} + +static OSStatus RemoveUserData( + void * self, + UInt32 inUserDataID, + UInt32 inIndex) +{ + return AFC->AFAPI_RemoveUserData(inUserDataID, inIndex); +} + +static OSStatus ExtensionIsThisFormat( + void * self, + CFStringRef inExtension, + UInt32 *outResult) +{ + AudioFileFormatBase* aff = AFC->GetAudioFileFormatBase(); + if (!aff) return kAudio_ParamError; + + UInt32 res = aff->ExtensionIsThisFormat(inExtension); + if (outResult) *outResult = res; + return noErr; +} + +static OSStatus FileDataIsThisFormat( + void * self, + UInt32 inDataByteSize, + const void* inData, + UInt32 *outResult) +{ + AudioFileFormatBase* aff = AFC->GetAudioFileFormatBase(); + if (!aff) return kAudio_ParamError; + + UncertainResult res = aff->FileDataIsThisFormat(inDataByteSize, inData); + if (outResult) *outResult = res; + return noErr; +} + +static OSStatus GetGlobalInfoSize( + void * self, + AudioFilePropertyID inPropertyID, + UInt32 inSpecifierSize, + const void* inSpecifier, + UInt32 *outPropertySize) +{ + return AFC->AFAPI_GetGlobalInfoSize(inPropertyID, inSpecifierSize, inSpecifier, outPropertySize); +} + +static OSStatus GetGlobalInfo( + void * self, + AudioFilePropertyID inPropertyID, + UInt32 inSpecifierSize, + const void* inSpecifier, + UInt32 *ioPropertySize, + void *ioPropertyData) +{ + return AFC->AFAPI_GetGlobalInfo(inPropertyID, inSpecifierSize, inSpecifier, ioPropertySize, ioPropertyData); +} + +//---------------------------------------------------------------------------------------- + + +AudioFileComponentBase::AudioFileComponentBase(AudioComponentInstance inInstance) + : ComponentBase(inInstance) +{ +} + +AudioFileComponentBase::~AudioFileComponentBase() +{ +} + +AudioFileObjectComponentBase::AudioFileObjectComponentBase(AudioComponentInstance inInstance) + : AudioFileComponentBase(inInstance), mAudioFileObject(0) +{ + // derived class should create an AudioFileObject here and if NULL, the AudioFormat as well. +} + +AudioFileObjectComponentBase::~AudioFileObjectComponentBase() +{ + delete mAudioFileObject; +} + +OSStatus AudioFileObjectComponentBase::AFAPI_CreateURL( + CFURLRef inFileRef, + const AudioStreamBasicDescription *inFormat, + UInt32 inFlags) +{ + if (!mAudioFileObject) return kAudio_ParamError; + + OSStatus result = mAudioFileObject->DoCreate (inFileRef, inFormat, inFlags); + return result; +} + + +OSStatus AudioFileObjectComponentBase::AFAPI_OpenURL( + CFURLRef inFileRef, + SInt8 inPermissions, + int inFD) +{ + if (!mAudioFileObject) return kAudio_ParamError; + + OSStatus result = mAudioFileObject->DoOpen(inFileRef, inPermissions, inFD); + return result; +} + + +OSStatus AudioFileObjectComponentBase::AFAPI_OpenWithCallbacks( + void * inRefCon, + AudioFile_ReadProc inReadFunc, + AudioFile_WriteProc inWriteFunc, + AudioFile_GetSizeProc inGetSizeFunc, + AudioFile_SetSizeProc inSetSizeFunc) +{ + if (!mAudioFileObject) return kAudio_ParamError; + return mAudioFileObject->DoOpenWithCallbacks(inRefCon, inReadFunc, inWriteFunc, inGetSizeFunc, inSetSizeFunc); +} + + +OSStatus AudioFileObjectComponentBase::AFAPI_InitializeWithCallbacks( + void * inRefCon, + AudioFile_ReadProc inReadFunc, + AudioFile_WriteProc inWriteFunc, + AudioFile_GetSizeProc inGetSizeFunc, + AudioFile_SetSizeProc inSetSizeFunc, + UInt32 inFileType, + const AudioStreamBasicDescription *inFormat, + UInt32 inFlags) +{ + if (!mAudioFileObject) return kAudio_ParamError; + return mAudioFileObject->DoInitializeWithCallbacks(inRefCon, inReadFunc, inWriteFunc, inGetSizeFunc, inSetSizeFunc, + inFileType, inFormat, inFlags); +} + + +OSStatus AudioFileObjectComponentBase::AFAPI_Close() +{ + if (!mAudioFileObject) return kAudio_ParamError; + return mAudioFileObject->DoClose(); +} + +OSStatus AudioFileObjectComponentBase::AFAPI_Optimize() +{ + if (!mAudioFileObject) return kAudio_ParamError; + return mAudioFileObject->DoOptimize(); +} + +OSStatus AudioFileObjectComponentBase::AFAPI_ReadBytes( + Boolean inUseCache, + SInt64 inStartingByte, + UInt32 *ioNumBytes, + void *outBuffer) +{ + if (!mAudioFileObject) return kAudio_ParamError; + return mAudioFileObject->ReadBytes(inUseCache, inStartingByte, ioNumBytes, outBuffer); +} + + +OSStatus AudioFileObjectComponentBase::AFAPI_WriteBytes( + Boolean inUseCache, + SInt64 inStartingByte, + UInt32 *ioNumBytes, + const void *inBuffer) +{ + if (!mAudioFileObject) return kAudio_ParamError; + return mAudioFileObject->WriteBytes(inUseCache, inStartingByte, ioNumBytes, inBuffer); +} + + + + +OSStatus AudioFileObjectComponentBase::AFAPI_ReadPackets( + Boolean inUseCache, + UInt32 *outNumBytes, + AudioStreamPacketDescription *outPacketDescriptions, + SInt64 inStartingPacket, + UInt32 *ioNumPackets, + void *outBuffer) +{ + if (!mAudioFileObject) return kAudio_ParamError; + return mAudioFileObject->ReadPackets(inUseCache, outNumBytes, outPacketDescriptions, + inStartingPacket, ioNumPackets, outBuffer); +} + +OSStatus AudioFileObjectComponentBase::AFAPI_ReadPacketData( + Boolean inUseCache, + UInt32 *ioNumBytes, + AudioStreamPacketDescription *outPacketDescriptions, + SInt64 inStartingPacket, + UInt32 *ioNumPackets, + void *outBuffer) +{ + if (!mAudioFileObject) return kAudio_ParamError; + return mAudioFileObject->ReadPacketData(inUseCache, ioNumBytes, outPacketDescriptions, + inStartingPacket, ioNumPackets, outBuffer); +} + + +OSStatus AudioFileObjectComponentBase::AFAPI_WritePackets( + Boolean inUseCache, + UInt32 inNumBytes, + const AudioStreamPacketDescription *inPacketDescriptions, + SInt64 inStartingPacket, + UInt32 *ioNumPackets, + const void *inBuffer) +{ + if (!mAudioFileObject) return kAudio_ParamError; + return mAudioFileObject->WritePackets(inUseCache, inNumBytes, inPacketDescriptions, + inStartingPacket, ioNumPackets, inBuffer); +} + + + +OSStatus AudioFileObjectComponentBase::AFAPI_GetPropertyInfo( + AudioFilePropertyID inPropertyID, + UInt32 *outDataSize, + UInt32 *isWritable) +{ + if (!mAudioFileObject) return kAudio_ParamError; + return mAudioFileObject->GetPropertyInfo(inPropertyID, outDataSize, isWritable); +} + + +OSStatus AudioFileObjectComponentBase::AFAPI_GetProperty( + AudioFilePropertyID inPropertyID, + UInt32 *ioPropertySize, + void *ioPropertyData) +{ + OSStatus err = noErr; + + if (!ioPropertyData) return kAudio_ParamError; + + if (!mAudioFileObject) return kAudio_ParamError; + err = mAudioFileObject->GetProperty(inPropertyID, ioPropertySize, ioPropertyData); + return err; +} + + +OSStatus AudioFileObjectComponentBase::AFAPI_SetProperty( + AudioFilePropertyID inPropertyID, + UInt32 inPropertySize, + const void *inPropertyData) +{ + if (!mAudioFileObject) return kAudio_ParamError; + return mAudioFileObject->SetProperty(inPropertyID, inPropertySize, inPropertyData); +} + + +OSStatus AudioFileObjectComponentBase::AFAPI_CountUserData( + UInt32 inUserDataID, + UInt32 *outNumberItems) +{ + if (!mAudioFileObject) return kAudio_ParamError; + return mAudioFileObject->CountUserData(inUserDataID, outNumberItems); +} + +OSStatus AudioFileObjectComponentBase::AFAPI_GetUserDataSize( + UInt32 inUserDataID, + UInt32 inIndex, + UInt32 *outUserDataSize) +{ + if (!mAudioFileObject) return kAudio_ParamError; + return mAudioFileObject->GetUserDataSize(inUserDataID, inIndex, outUserDataSize); +} + +OSStatus AudioFileObjectComponentBase::AFAPI_GetUserData( + UInt32 inUserDataID, + UInt32 inIndex, + UInt32 *ioUserDataSize, + void *outUserData) +{ + if (!mAudioFileObject) return kAudio_ParamError; + return mAudioFileObject->GetUserData(inUserDataID, inIndex, ioUserDataSize, outUserData); +} + +OSStatus AudioFileObjectComponentBase::AFAPI_SetUserData( + UInt32 inUserDataID, + UInt32 inIndex, + UInt32 inUserDataSize, + const void *inUserData) +{ + if (!mAudioFileObject) return kAudio_ParamError; + return mAudioFileObject->SetUserData(inUserDataID, inIndex, inUserDataSize, inUserData); +} + +OSStatus AudioFileObjectComponentBase::AFAPI_RemoveUserData( + UInt32 inUserDataID, + UInt32 inIndex) +{ + if (!mAudioFileObject) return kAudio_ParamError; + return mAudioFileObject->RemoveUserData(inUserDataID, inIndex); +} + + +OSStatus AudioFileComponentBase::AFAPI_GetGlobalInfoSize( + AudioFilePropertyID inPropertyID, + UInt32 inSpecifierSize, + const void* inSpecifier, + UInt32 *outPropertySize) +{ + OSStatus err = noErr; + + switch (inPropertyID) + { + case kAudioFileComponent_CanRead : + case kAudioFileComponent_CanWrite : + *outPropertySize = sizeof(UInt32); + break; + + case kAudioFileComponent_FileTypeName : + *outPropertySize = sizeof(CFStringRef); + break; + + case kAudioFileComponent_ExtensionsForType : + *outPropertySize = sizeof(CFArrayRef); + break; + + case kAudioFileComponent_UTIsForType : + *outPropertySize = sizeof(CFArrayRef); + break; + + case kAudioFileComponent_MIMETypesForType : + *outPropertySize = sizeof(CFArrayRef); + break; + + case kAudioFileComponent_AvailableFormatIDs : + { + UInt32 size = 0xFFFFFFFF; + err = GetAudioFileFormatBase()->GetAvailableFormatIDs(&size, NULL); + if (!err) *outPropertySize = size; + break; + } + case kAudioFileComponent_HFSTypeCodesForType : + { + UInt32 size = 0xFFFFFFFF; + err = GetAudioFileFormatBase()->GetHFSCodes(&size, NULL); + if (!err) *outPropertySize = size; + break; + } + case kAudioFileComponent_AvailableStreamDescriptionsForFormat : + { + if (inSpecifierSize != sizeof(UInt32)) return kAudioFileBadPropertySizeError; + UInt32 inFormatID = *(UInt32*)inSpecifier; + err = GetAudioFileFormatBase()->GetAvailableStreamDescriptions(inFormatID, outPropertySize, NULL); + } + break; + + default: + err = kAudioFileUnsupportedPropertyError; + } + return err; +} + + +OSStatus AudioFileComponentBase::AFAPI_GetGlobalInfo( + AudioFilePropertyID inPropertyID, + UInt32 inSpecifierSize, + const void* inSpecifier, + UInt32 *ioPropertySize, + void *ioPropertyData) +{ + OSStatus err = noErr; + + if (!ioPropertyData || !ioPropertySize) return kAudio_ParamError; + + switch (inPropertyID) + { + case kAudioFileComponent_CanRead : + { + if (*ioPropertySize != sizeof(UInt32)) return kAudioFileBadPropertySizeError; + UInt32* flag = (UInt32*)ioPropertyData; + *flag = GetAudioFileFormatBase()->CanRead(); + } + break; + + case kAudioFileComponent_CanWrite : + { + if (*ioPropertySize != sizeof(UInt32)) return kAudioFileBadPropertySizeError; + UInt32* flag = (UInt32*)ioPropertyData; + *flag = GetAudioFileFormatBase()->CanWrite(); + } + break; + + case kAudioFileComponent_FileTypeName : + { + if (*ioPropertySize != sizeof(CFStringRef)) return kAudioFileBadPropertySizeError; + CFStringRef* name = (CFStringRef*)ioPropertyData; + GetAudioFileFormatBase()->GetFileTypeName(name); + } + break; + + case kAudioFileComponent_ExtensionsForType : + { + if (*ioPropertySize != sizeof(CFArrayRef)) return kAudioFileBadPropertySizeError; + CFArrayRef* array = (CFArrayRef*)ioPropertyData; + GetAudioFileFormatBase()->GetExtensions(array); + } + break; + + case kAudioFileComponent_UTIsForType : + { + if (*ioPropertySize != sizeof(CFArrayRef)) return kAudioFileBadPropertySizeError; + CFArrayRef* array = (CFArrayRef*)ioPropertyData; + GetAudioFileFormatBase()->GetUTIs(array); + } + break; + + case kAudioFileComponent_MIMETypesForType : + { + if (*ioPropertySize != sizeof(CFArrayRef)) return kAudioFileBadPropertySizeError; + CFArrayRef* array = (CFArrayRef*)ioPropertyData; + GetAudioFileFormatBase()->GetMIMETypes(array); + } + break; + + case kAudioFileComponent_HFSTypeCodesForType : + { + err = GetAudioFileFormatBase()->GetHFSCodes(ioPropertySize, ioPropertyData); + } + break; + + case kAudioFileComponent_AvailableFormatIDs : + { + err = GetAudioFileFormatBase()->GetAvailableFormatIDs(ioPropertySize, ioPropertyData); + } + break; + + case kAudioFileComponent_AvailableStreamDescriptionsForFormat : + { + if (inSpecifierSize != sizeof(UInt32)) return kAudioFileBadPropertySizeError; + UInt32 inFormatID = *(UInt32*)inSpecifier; + err = GetAudioFileFormatBase()->GetAvailableStreamDescriptions(inFormatID, ioPropertySize, ioPropertyData); + } + break; + + default: + err = kAudioFileUnsupportedPropertyError; + } + return err; +} + + +#if !CA_USE_AUDIO_PLUGIN_ONLY +OSStatus AudioFileComponentBase::ComponentEntryDispatch(ComponentParameters* params, AudioFileComponentBase* inThis) +{ + OSStatus result = noErr; + if (inThis == NULL) return kAudio_ParamError; + + try + { + switch (params->what) + { + case kComponentCanDoSelect: + switch (GetSelectorForCanDo(params)) + { + case kAudioFileCreateURLSelect: + case kAudioFileOpenURLSelect: + case kAudioFileOpenWithCallbacksSelect: + case kAudioFileInitializeWithCallbacksSelect: + case kAudioFileCloseSelect: + case kAudioFileOptimizeSelect: + case kAudioFileReadBytesSelect: + case kAudioFileWriteBytesSelect: + case kAudioFileReadPacketsSelect: + case kAudioFileWritePacketsSelect: + case kAudioFileGetPropertyInfoSelect: + case kAudioFileGetPropertySelect: + case kAudioFileSetPropertySelect: + case kAudioFileExtensionIsThisFormatSelect: + case kAudioFileFileDataIsThisFormatSelect: + case kAudioFileGetGlobalInfoSizeSelect: + case kAudioFileGetGlobalInfoSelect: + + case kAudioFileCountUserDataSelect: + case kAudioFileGetUserDataSizeSelect: + case kAudioFileGetUserDataSelect: + case kAudioFileSetUserDataSelect: + case kAudioFileRemoveUserDataSelect: + result = 1; + break; + default: + // these are no longer supported +/* case kAudioFileCreateSelect: + case kAudioFileOpenSelect: + case kAudioFileInitializeSelect: +*/ result = ComponentBase::ComponentEntryDispatch(params, inThis); + }; + break; + + case kAudioFileCreateURLSelect: + { + PARAM(CFURLRef, inFileRef, 0, 3); + PARAM(const AudioStreamBasicDescription*, inFormat, 1, 3); + PARAM(UInt32, inFlags, 2, 3); + + result = inThis->AFAPI_CreateURL(inFileRef, inFormat, inFlags); + } + break; + case kAudioFileOpenURLSelect: + { + PARAM(CFURLRef, inFileRef, 0, 3); + PARAM(SInt32, inPermissions, 1, 3); + PARAM(int, inFileDescriptor, 2, 3); + + result = inThis->AFAPI_OpenURL(inFileRef, inPermissions, inFileDescriptor); + } + break; + case kAudioFileOpenWithCallbacksSelect: + { + PARAM(void*, inRefCon, 0, 5); + PARAM(AudioFile_ReadProc, inReadFunc, 1, 5); + PARAM(AudioFile_WriteProc, inWriteFunc, 2, 5); + PARAM(AudioFile_GetSizeProc, inGetSizeFunc, 3, 5); + PARAM(AudioFile_SetSizeProc, inSetSizeFunc, 4, 5); + + result = inThis->AFAPI_OpenWithCallbacks(inRefCon, inReadFunc, inWriteFunc, + inGetSizeFunc, inSetSizeFunc); + } + break; + case kAudioFileInitializeWithCallbacksSelect: + { + PARAM(void*, inRefCon, 0, 8); + PARAM(AudioFile_ReadProc, inReadFunc, 1, 8); + PARAM(AudioFile_WriteProc, inWriteFunc, 2, 8); + PARAM(AudioFile_GetSizeProc, inGetSizeFunc, 3, 8); + PARAM(AudioFile_SetSizeProc, inSetSizeFunc, 4, 8); + PARAM(UInt32, inFileType, 5, 8); + PARAM(const AudioStreamBasicDescription*, inFormat, 6, 8); + PARAM(UInt32, inFlags, 7, 8); + + result = inThis->AFAPI_InitializeWithCallbacks(inRefCon, inReadFunc, inWriteFunc, + inGetSizeFunc, inSetSizeFunc, + inFileType, inFormat, inFlags); + } + break; + case kAudioFileCloseSelect: + { + result = inThis->AFAPI_Close(); + } + break; + case kAudioFileOptimizeSelect: + { + result = inThis->AFAPI_Optimize(); + } + break; + case kAudioFileReadBytesSelect: + { + PARAM(UInt32, inUseCache, 0, 4); + PARAM(SInt64*, inStartingByte, 1, 4); + PARAM(UInt32*, ioNumBytes, 2, 4); + PARAM(void*, outBuffer, 3, 4); + + result = inThis->AFAPI_ReadBytes(inUseCache, *inStartingByte, ioNumBytes, + outBuffer); + } + break; + case kAudioFileWriteBytesSelect: + { + PARAM(UInt32, inUseCache, 0, 4); + PARAM(SInt64*, inStartingByte, 1, 4); + PARAM(UInt32*, ioNumBytes, 2, 4); + PARAM(const void*, inBuffer, 3, 4); + + result = inThis->AFAPI_WriteBytes(inUseCache, *inStartingByte, ioNumBytes, + inBuffer); + } + break; + case kAudioFileReadPacketsSelect: + { + PARAM(UInt32, inUseCache, 0, 6); + PARAM(UInt32*, outNumBytes, 1, 6); + PARAM(AudioStreamPacketDescription*, outPacketDescriptions, 2, 6); + PARAM(SInt64*, inStartingPacket, 3, 6); + PARAM(UInt32*, ioNumPackets, 4, 6); + PARAM(void*, outBuffer, 5, 6); + + result = inThis->AFAPI_ReadPackets(inUseCache, outNumBytes, outPacketDescriptions, + *inStartingPacket, ioNumPackets, outBuffer); + } + break; + case kAudioFileWritePacketsSelect: + { + PARAM(UInt32, inUseCache, 0, 6); + PARAM(UInt32, inNumBytes, 1, 6); + PARAM(const AudioStreamPacketDescription*, inPacketDescriptions, 2, 6); + PARAM(SInt64*, inStartingPacket, 3, 6); + PARAM(UInt32*, ioNumPackets, 4, 6); + PARAM(const void*, inBuffer, 5, 6); + + result = inThis->AFAPI_WritePackets(inUseCache, inNumBytes, inPacketDescriptions, + *inStartingPacket, ioNumPackets, inBuffer); + } + break; + + case kAudioFileGetPropertyInfoSelect: + { + PARAM(AudioFileComponentPropertyID, inPropertyID, 0, 3); + PARAM(UInt32*, outPropertySize, 1, 3); + PARAM(UInt32*, outWritable, 2, 3); + + result = inThis->AFAPI_GetPropertyInfo(inPropertyID, outPropertySize, outWritable); + } + break; + + case kAudioFileGetPropertySelect: + { + PARAM(AudioFileComponentPropertyID, inPropertyID, 0, 3); + PARAM(UInt32*, ioPropertyDataSize, 1, 3); + PARAM(void*, outPropertyData, 2, 3); + + result = inThis->AFAPI_GetProperty(inPropertyID, ioPropertyDataSize, outPropertyData); + } + break; + case kAudioFileSetPropertySelect: + { + PARAM(AudioFileComponentPropertyID, inPropertyID, 0, 3); + PARAM(UInt32, inPropertyDataSize, 1, 3); + PARAM(const void*, inPropertyData, 2, 3); + + result = inThis->AFAPI_SetProperty(inPropertyID, inPropertyDataSize, inPropertyData); + } + break; + + case kAudioFileGetGlobalInfoSizeSelect: + { + PARAM(AudioFileComponentPropertyID, inPropertyID, 0, 4); + PARAM(UInt32, inSpecifierSize, 1, 4); + PARAM(const void*, inSpecifier, 2, 4); + PARAM(UInt32*, outPropertyDataSize, 3, 4); + + result = inThis->AFAPI_GetGlobalInfoSize(inPropertyID, inSpecifierSize, inSpecifier, + outPropertyDataSize); + } + break; + case kAudioFileGetGlobalInfoSelect: + { + PARAM(AudioFileComponentPropertyID, inPropertyID, 0, 5); + PARAM(UInt32, inSpecifierSize, 1, 5); + PARAM(const void*, inSpecifier, 2, 5); + PARAM(UInt32*, ioPropertyDataSize, 3, 5); + PARAM(void*, outPropertyData, 4, 5); + + result = inThis->AFAPI_GetGlobalInfo(inPropertyID, inSpecifierSize, inSpecifier, + ioPropertyDataSize, outPropertyData); + } + break; + + case kAudioFileExtensionIsThisFormatSelect: + { + PARAM(CFStringRef, inExtension, 0, 2); + PARAM(UInt32*, outResult, 1, 2); + + AudioFileFormatBase* aff = inThis->GetAudioFileFormatBase(); + if (!aff) return kAudio_ParamError; + + UInt32 res = aff->ExtensionIsThisFormat(inExtension); + if (outResult) *outResult = res; + } + break; + + case kAudioFileFileDataIsThisFormatSelect: + { + PARAM(UInt32, inDataByteSize, 0, 3); + PARAM(const void*, inData, 1, 3); + PARAM(UInt32*, outResult, 2, 3); + + AudioFileFormatBase* aff = inThis->GetAudioFileFormatBase(); + if (!aff) return kAudio_ParamError; + + UncertainResult res = aff->FileDataIsThisFormat(inDataByteSize, inData); + if (outResult) *outResult = res; + } + break; + + case kAudioFileCountUserDataSelect: + { + PARAM(UInt32, inUserDataID, 0, 2); + PARAM(UInt32*, outNumberItems, 1, 2); + + result = inThis->AFAPI_CountUserData(inUserDataID, outNumberItems); + } + break; + + case kAudioFileGetUserDataSizeSelect: + { + PARAM(UInt32, inUserDataID, 0, 3); + PARAM(UInt32, inIndex, 1, 3); + PARAM(UInt32*, outUserDataSize, 2, 3); + + result = inThis->AFAPI_GetUserDataSize(inUserDataID, inIndex, outUserDataSize); + } + break; + + case kAudioFileGetUserDataSelect: + { + PARAM(UInt32, inUserDataID, 0, 4); + PARAM(UInt32, inIndex, 1, 4); + PARAM(UInt32*, ioUserDataSize, 2, 4); + PARAM(void*, outUserData, 3, 4); + + result = inThis->AFAPI_GetUserData(inUserDataID, inIndex, + ioUserDataSize, outUserData); + } + break; + + case kAudioFileSetUserDataSelect: + { + PARAM(UInt32, inUserDataID, 0, 4); + PARAM(UInt32, inIndex, 1, 4); + PARAM(UInt32, inUserDataSize, 2, 4); + PARAM(const void*, inUserData, 3, 4); + + result = inThis->AFAPI_SetUserData(inUserDataID, inIndex, + inUserDataSize, inUserData); + } + break; + + case kAudioFileRemoveUserDataSelect: + { + PARAM(UInt32, inUserDataID, 0, 2); + PARAM(UInt32, inIndex, 1, 2); + + result = inThis->AFAPI_RemoveUserData(inUserDataID, inIndex); + } + break; + + + default: + result = ComponentBase::ComponentEntryDispatch(params, inThis); + break; + } + } + COMPONENT_CATCH + return result; +} +#endif + +AudioComponentMethod AudioFileComponentLookup::Lookup (SInt16 selector) +{ + switch (selector) { + +#define DefCase(NAME) case kAudioFile##NAME##Select: return (AudioComponentMethod)NAME + + DefCase(OpenWithCallbacks); + DefCase(InitializeWithCallbacks); + DefCase(Close); + DefCase(Optimize); + DefCase(ReadBytes); + DefCase(WriteBytes); + DefCase(ReadPackets); + DefCase(WritePackets); + DefCase(GetPropertyInfo); + DefCase(GetProperty); + DefCase(SetProperty); + + DefCase(ExtensionIsThisFormat); + DefCase(GetGlobalInfoSize); + DefCase(GetGlobalInfo); + + DefCase(CountUserData); + DefCase(GetUserDataSize); + DefCase(GetUserData); + DefCase(SetUserData); + DefCase(RemoveUserData); + DefCase(CreateURL); + DefCase(OpenURL); + DefCase(FileDataIsThisFormat); + DefCase(ReadPacketData); + + // These selectors are deprecated and do not appear: Create, Open, Initialize, FileIsThisFormat, DataIsThisFormat. + + default: + break; + } + return NULL; +} diff --git a/libs/appleutility/CoreAudio/AudioFile/AFPublic/AudioFileComponentBase.h b/libs/appleutility/CoreAudio/AudioFile/AFPublic/AudioFileComponentBase.h new file mode 100644 index 0000000000..5a11934e76 --- /dev/null +++ b/libs/appleutility/CoreAudio/AudioFile/AFPublic/AudioFileComponentBase.h @@ -0,0 +1,311 @@ +/* + File: AudioFileComponentBase.h + Abstract: Part of CoreAudio Utility Classes + Version: 1.1 + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple + 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 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. + + Copyright (C) 2014 Apple Inc. All Rights Reserved. + +*/ +#ifndef __AudioFileComponentBase_h__ +#define __AudioFileComponentBase_h__ + +#include "ComponentBase.h" +#include "AudioFileFormat.h" + +struct AudioFileComponentLookup { + static AudioComponentMethod Lookup (SInt16 selector); +}; +template <class Implementor> +class AudioFileComponentFactory : public APFactory<AudioFileComponentLookup, Implementor> +{ +}; + +/* subclass, override AudioFileComponentBase() and GetAudioFormat() and that's it. */ + +class AudioFileComponentBase : public ComponentBase +{ +public: + AudioFileComponentBase(AudioComponentInstance inInstance); + virtual ~AudioFileComponentBase(); + + virtual AudioFileFormatBase* GetAudioFileFormatBase() const = 0; + + /* Public API Function Support */ + virtual OSStatus AFAPI_CreateURL( + CFURLRef inFileRef, + const AudioStreamBasicDescription *inFormat, + UInt32 inFlags) { return kAudio_UnimplementedError; } + + virtual OSStatus AFAPI_OpenURL( + CFURLRef inFileRef, + SInt8 inPermissions, + int inFD) { return kAudio_UnimplementedError; } + + + virtual OSStatus AFAPI_Create( + const FSRef *inParentRef, + CFStringRef inFileName, + const AudioStreamBasicDescription *inFormat, + UInt32 inFlags, + FSRef *outNewFileRef) { return kAudio_UnimplementedError; } + + virtual OSStatus AFAPI_Initialize( + const FSRef *inFileRef, + const AudioStreamBasicDescription *inFormat, + UInt32 inFlags) { return kAudio_UnimplementedError; } + + virtual OSStatus AFAPI_Open( + const FSRef *inFileRef, + SInt8 inPermissions, + SInt16 inRefNum) { return kAudio_UnimplementedError; } + + virtual OSStatus AFAPI_OpenWithCallbacks( + void * inRefCon, + AudioFile_ReadProc inReadFunc, + AudioFile_WriteProc inWriteFunc, + AudioFile_GetSizeProc inGetSizeFunc, + AudioFile_SetSizeProc inSetSizeFunc)=0; + + virtual OSStatus AFAPI_InitializeWithCallbacks( + void * inRefCon, + AudioFile_ReadProc inReadFunc, + AudioFile_WriteProc inWriteFunc, + AudioFile_GetSizeProc inGetSizeFunc, + AudioFile_SetSizeProc inSetSizeFunc, + UInt32 inFileType, + const AudioStreamBasicDescription *inFormat, + UInt32 inFlags)=0; + + virtual OSStatus AFAPI_Close()=0; + virtual OSStatus AFAPI_Optimize()=0; + virtual OSStatus AFAPI_ReadBytes( Boolean inUseCache, + SInt64 inStartingByte, + UInt32 *ioNumBytes, + void *outBuffer)=0; + + virtual OSStatus AFAPI_WriteBytes( Boolean inUseCache, + SInt64 inStartingByte, + UInt32 *ioNumBytes, + const void *inBuffer)=0; + + virtual OSStatus AFAPI_ReadPackets( Boolean inUseCache, + UInt32 *outNumBytes, + AudioStreamPacketDescription *outPacketDescriptions, + SInt64 inStartingPacket, + UInt32 *ioNumPackets, + void *outBuffer)=0; + + virtual OSStatus AFAPI_ReadPacketData( Boolean inUseCache, + UInt32 *ioNumBytes, + AudioStreamPacketDescription *outPacketDescriptions, + SInt64 inStartingPacket, + UInt32 *ioNumPackets, + void *outBuffer)=0; + + virtual OSStatus AFAPI_WritePackets( Boolean inUseCache, + UInt32 inNumBytes, + const AudioStreamPacketDescription *inPacketDescriptions, + SInt64 inStartingPacket, + UInt32 *ioNumPackets, + const void *inBuffer)=0; + + virtual OSStatus AFAPI_GetPropertyInfo( AudioFilePropertyID inPropertyID, + UInt32 *outDataSize, + UInt32 *isWritable)=0; + + virtual OSStatus AFAPI_GetProperty( AudioFilePropertyID inPropertyID, + UInt32 *ioDataSize, + void *ioPropertyData)=0; + + virtual OSStatus AFAPI_SetProperty( AudioFilePropertyID inPropertyID, + UInt32 inDataSize, + const void *inPropertyData)=0; + virtual OSStatus AFAPI_GetGlobalInfoSize( + AudioFilePropertyID inPropertyID, + UInt32 inSpecifierSize, + const void* inSpecifier, + UInt32 *outPropertySize); + + virtual OSStatus AFAPI_GetGlobalInfo( + AudioFilePropertyID inPropertyID, + UInt32 inSpecifierSize, + const void* inSpecifier, + UInt32 *ioPropertySize, + void *ioPropertyData); + + virtual OSStatus AFAPI_CountUserData( UInt32 inUserDataID, + UInt32 *outNumberItems)=0; + + virtual OSStatus AFAPI_GetUserDataSize( UInt32 inUserDataID, + UInt32 inIndex, + UInt32 *outDataSize)=0; + + virtual OSStatus AFAPI_GetUserData( UInt32 inUserDataID, + UInt32 inIndex, + UInt32 *ioDataSize, + void *ioUserData)=0; + + virtual OSStatus AFAPI_SetUserData( UInt32 inUserDataID, + UInt32 inIndex, + UInt32 inDataSize, + const void *inUserData)=0; + + virtual OSStatus AFAPI_RemoveUserData( UInt32 inUserDataID, + UInt32 inIndex)=0; +#if !CA_USE_AUDIO_PLUGIN_ONLY + static OSStatus ComponentEntryDispatch(ComponentParameters *p, AudioFileComponentBase *This); +#endif + +protected: +}; + + + +class AudioFileObjectComponentBase : public AudioFileComponentBase +{ +public: + AudioFileObjectComponentBase(AudioComponentInstance inInstance); + virtual ~AudioFileObjectComponentBase(); + + virtual AudioFileFormat* GetAudioFormat() const = 0; + virtual AudioFileFormatBase* GetAudioFileFormatBase() const { return GetAudioFormat(); } + + void SetAudioFileObject(AudioFileObject* inObject) { mAudioFileObject = inObject; } + + /* Public API Function Support */ + + virtual OSStatus AFAPI_CreateURL( + CFURLRef inFileRef, + const AudioStreamBasicDescription *inFormat, + UInt32 inFlags); + + virtual OSStatus AFAPI_OpenURL( + CFURLRef inFileRef, + SInt8 inPermissions, + int inFD); + + virtual OSStatus AFAPI_OpenWithCallbacks( + void * inRefCon, + AudioFile_ReadProc inReadFunc, + AudioFile_WriteProc inWriteFunc, + AudioFile_GetSizeProc inGetSizeFunc, + AudioFile_SetSizeProc inSetSizeFunc); + + virtual OSStatus AFAPI_InitializeWithCallbacks( + void * inRefCon, + AudioFile_ReadProc inReadFunc, + AudioFile_WriteProc inWriteFunc, + AudioFile_GetSizeProc inGetSizeFunc, + AudioFile_SetSizeProc inSetSizeFunc, + UInt32 inFileType, + const AudioStreamBasicDescription *inFormat, + UInt32 inFlags); + + virtual OSStatus AFAPI_Close(); + virtual OSStatus AFAPI_Optimize(); + virtual OSStatus AFAPI_ReadBytes( Boolean inUseCache, + SInt64 inStartingByte, + UInt32 *ioNumBytes, + void *outBuffer); + + virtual OSStatus AFAPI_WriteBytes( Boolean inUseCache, + SInt64 inStartingByte, + UInt32 *ioNumBytes, + const void *inBuffer); + + virtual OSStatus AFAPI_ReadPackets( Boolean inUseCache, + UInt32 *outNumBytes, + AudioStreamPacketDescription *outPacketDescriptions, + SInt64 inStartingPacket, + UInt32 *ioNumPackets, + void *outBuffer); + + virtual OSStatus AFAPI_ReadPacketData( Boolean inUseCache, + UInt32 *ioNumBytes, + AudioStreamPacketDescription *outPacketDescriptions, + SInt64 inStartingPacket, + UInt32 *ioNumPackets, + void *outBuffer); + + virtual OSStatus AFAPI_WritePackets( Boolean inUseCache, + UInt32 inNumBytes, + const AudioStreamPacketDescription *inPacketDescriptions, + SInt64 inStartingPacket, + UInt32 *ioNumPackets, + const void *inBuffer); + + virtual OSStatus AFAPI_GetPropertyInfo( AudioFilePropertyID inPropertyID, + UInt32 *outDataSize, + UInt32 *isWritable); + + virtual OSStatus AFAPI_GetProperty( AudioFilePropertyID inPropertyID, + UInt32 *ioDataSize, + void *ioPropertyData); + + virtual OSStatus AFAPI_SetProperty( AudioFilePropertyID inPropertyID, + UInt32 inDataSize, + const void *inPropertyData); + + virtual OSStatus AFAPI_CountUserData( UInt32 inUserDataID, + UInt32 *outNumberItems); + + virtual OSStatus AFAPI_GetUserDataSize( UInt32 inUserDataID, + UInt32 inIndex, + UInt32 *outDataSize); + + virtual OSStatus AFAPI_GetUserData( UInt32 inUserDataID, + UInt32 inIndex, + UInt32 *ioDataSize, + void *ioUserData); + + virtual OSStatus AFAPI_SetUserData( UInt32 inUserDataID, + UInt32 inIndex, + UInt32 inDataSize, + const void *inUserData); + + virtual OSStatus AFAPI_RemoveUserData( UInt32 inUserDataID, + UInt32 inIndex); + +protected: + AudioFileObject* mAudioFileObject; +}; + +#endif diff --git a/libs/appleutility/CoreAudio/AudioFile/AFPublic/AudioFileFormat.cpp b/libs/appleutility/CoreAudio/AudioFile/AFPublic/AudioFileFormat.cpp new file mode 100644 index 0000000000..ee6bedd593 --- /dev/null +++ b/libs/appleutility/CoreAudio/AudioFile/AFPublic/AudioFileFormat.cpp @@ -0,0 +1,71 @@ +/* + File: AudioFileFormat.cpp + Abstract: AudioFileFormat.h + Version: 1.1 + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple + 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 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. + + Copyright (C) 2014 Apple Inc. All Rights Reserved. + +*/ +#include "AudioFileFormat.h" +#include "DataSource.h" + +AudioFileFormatBase::AudioFileFormatBase(UInt32 inFileType) + : mFileType(inFileType) +{ +} + +AudioFileFormatBase::~AudioFileFormatBase() +{ +} + +OSStatus AudioFileFormatBase::GetHFSCodes(UInt32* ioDataSize, void* outPropertyData) +{ + return kAudioFileUnsupportedPropertyError; +} + +AudioFileFormat::AudioFileFormat(UInt32 inFileType) + : AudioFileFormatBase(inFileType) +{ +} + +AudioFileFormat::~AudioFileFormat() +{ +} diff --git a/libs/appleutility/CoreAudio/AudioFile/AFPublic/AudioFileFormat.h b/libs/appleutility/CoreAudio/AudioFile/AFPublic/AudioFileFormat.h new file mode 100644 index 0000000000..9436199569 --- /dev/null +++ b/libs/appleutility/CoreAudio/AudioFile/AFPublic/AudioFileFormat.h @@ -0,0 +1,125 @@ +/* + File: AudioFileFormat.h + Abstract: Part of CoreAudio Utility Classes + Version: 1.1 + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple + 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 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. + + Copyright (C) 2014 Apple Inc. All Rights Reserved. + +*/ +#ifndef _AudioFileFormat_H_ +#define _AudioFileFormat_H_ + +#include "AudioFileObject.h" + +// AudioFileFormat is a factory class for AudioFileObjects. + +// UncertainResult is needed for DataIsThisFormat. +// In the case of SoundDesigner 2 we can't determine if the data is SoundDesigner 2 or not. + +typedef int UncertainResult; + +enum { + kFalse = 0, + kTrue = 1, + kCantDetermine = -1 +}; + +class AudioFileHandle; +class AudioFileFormat; +class AudioFileFormatComponent; + +class AudioFileFormatBase +{ +public: + AudioFileFormatBase(UInt32 inFileType); + virtual ~AudioFileFormatBase(); + + // return true if extension is of this format type + virtual Boolean ExtensionIsThisFormat(CFStringRef inExtension) = 0; + + virtual UncertainResult FileDataIsThisFormat( + UInt32 /*inDataByteSize*/, + const void* /*inData*/) = 0; + + // support SoundDesigner II files while minimizing opening and closing files. + virtual Boolean ResourceIsThisFormat(const FSRef* /*inRef*/) { return false; } + + UInt32 GetFileType() const { return mFileType; } + + virtual UInt32 CanRead() const { return 1; } + virtual UInt32 CanWrite() const { return 1; } + virtual UInt32 HasResourceFork() const { return 0; } + + virtual void GetExtensions(CFArrayRef *outArray) = 0; + virtual void GetUTIs(CFArrayRef *outArray) {} + virtual void GetMIMETypes(CFArrayRef *outArray) {} + virtual void GetFileTypeName(CFStringRef *outName) = 0; + virtual OSStatus GetAvailableFormatIDs(UInt32* ioDataSize, void* outPropertyData) = 0; + virtual OSStatus GetAvailableStreamDescriptions(UInt32 inFormatID, UInt32* ioDataSize, void* outPropertyData) = 0; + virtual OSStatus GetHFSCodes(UInt32* ioDataSize, void* outPropertyData); + + virtual AudioFileFormat* AsAudioFileFormat() { return NULL; } + virtual AudioFileFormatComponent* AsAudioFileFormatComponent() { return NULL; } + +private: + UInt32 mFileType; +}; + +class AudioFileStreamObject; + +class AudioFileFormat : public AudioFileFormatBase +{ +public: + AudioFileFormat(UInt32 inFileType); + virtual ~AudioFileFormat(); + + // create an AudioFileObject for this format type. + virtual AudioFileObject* New() = 0; + virtual AudioFileStreamObject* NewStream() { return NULL; } + + // return true if file is of this format type + virtual UncertainResult FileDataIsThisFormat(UInt32 inDataByteSize, const void* inData) = 0; + + virtual AudioFileFormat* AsAudioFileFormat() { return this; } +}; + + +#endif diff --git a/libs/appleutility/CoreAudio/AudioFile/AFPublic/AudioFileObject.cpp b/libs/appleutility/CoreAudio/AudioFile/AFPublic/AudioFileObject.cpp new file mode 100644 index 0000000000..1a00f96251 --- /dev/null +++ b/libs/appleutility/CoreAudio/AudioFile/AFPublic/AudioFileObject.cpp @@ -0,0 +1,1966 @@ +/* + File: AudioFileObject.cpp + Abstract: AudioFileObject.h + Version: 1.1 + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple + 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 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. + + Copyright (C) 2014 Apple Inc. All Rights Reserved. + +*/ +#include "AudioFileObject.h" +#include "CADebugMacros.h" +#include <algorithm> +#include <sys/stat.h> + +#define kAudioFileNoCacheMask 0x20 + +const SInt64 kScanToEnd = 0x7fffFFFFffffFFFFLL; + +////////////////////////////////////////////////////////////////////////////////////////////////////////// + +AudioFileObject::~AudioFileObject() +{ + delete mDataSource; + DeletePacketTable(); + SetURL(NULL); +} + +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +OSStatus AudioFileObject::DoCreate( + CFURLRef inFileRef, + const AudioStreamBasicDescription *inFormat, + UInt32 inFlags) +{ + // common prologue + if (!IsDataFormatValid(inFormat)) + return kAudioFileUnsupportedDataFormatError; + + if (!IsDataFormatSupported(inFormat)) + return kAudioFileUnsupportedDataFormatError; + + SetPermissions(kAudioFileReadWritePermission); + + SetAlignDataWithFillerChunks(!(inFlags & 2 /* kAudioFileFlags_DontPageAlignAudioData */ )); + + // call virtual method for particular format. + return Create(inFileRef, inFormat); +} + +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +OSStatus AudioFileObject::Create( + CFURLRef inFileRef, + const AudioStreamBasicDescription *inFormat) +{ + int fileD; + OSStatus err = CreateDataFile (inFileRef, fileD); + FailIf (err != noErr, Bail, "CreateDataFile failed"); + + SetURL (inFileRef); + + err = OpenFile(kAudioFileReadWritePermission, fileD); + FailIf (err != noErr, Bail, "OpenFile failed"); + + err = SetDataFormat(inFormat); + FailIf (err != noErr, Bail, "SetDataFormat failed"); + + mIsInitialized = false; + +Bail: + return err; +} + +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +OSStatus AudioFileObject::DoOpen( + CFURLRef inFileRef, + SInt8 inPermissions, + int inFD) +{ + OSStatus err = noErr; + SetPermissions(inPermissions); + + err = Open(inFileRef, inPermissions, inFD); + FailIf (err != noErr, Bail, "Open failed"); + + err = ValidateFormatAndData(); + FailIf (err != noErr, Bail, "ValidateFormatAndData failed"); + +Bail: + return err; +} + +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +OSStatus AudioFileObject::Open( + CFURLRef inFileRef, + SInt8 inPermissions, + int inFD) +{ + if (!(inPermissions & kAudioFileReadPermission)) + return kAudioFilePermissionsError; // file must have read permissions + + SetURL(inFileRef); + + OSStatus err = OpenFile(inPermissions, inFD); + FailIf (err != noErr, Bail, "OpenFile failed"); + + err = OpenFromDataSource(); + FailIf (err != noErr, Bail, "OpenFromDataSource failed"); + +Bail: + return err; +} + +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +OSStatus AudioFileObject::ValidateFormatAndData() +{ + + + AudioStreamBasicDescription asbd = GetDataFormat(); + + if (!IsDataFormatValid(&asbd)) + return kAudioFileInvalidFileError; + + if (asbd.mFormatID == kAudioFormatLinearPCM) + { + SInt64 maxPackets = GetNumBytes() / asbd.mBytesPerPacket; + if (GetNumPackets() > maxPackets) + return kAudioFileInvalidFileError; + } + return noErr; +} + +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +OSStatus AudioFileObject::DoOpenWithCallbacks( + void * inRefCon, + AudioFile_ReadProc inReadFunc, + AudioFile_WriteProc inWriteFunc, + AudioFile_GetSizeProc inGetSizeFunc, + AudioFile_SetSizeProc inSetSizeFunc) +{ + SInt8 perms = (inSetSizeFunc || inWriteFunc) ? kAudioFileReadWritePermission : kAudioFileReadPermission; + SetPermissions(perms); + + DataSource* dataSource = new Seekable_DataSource(inRefCon, inReadFunc, inWriteFunc, inGetSizeFunc, inSetSizeFunc); + SetDataSource(dataSource); + return OpenFromDataSource(); +} + +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +OSStatus AudioFileObject::OpenFromDataSource(void) +{ + return noErr; +} + + +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +OSStatus AudioFileObject::DoInitializeWithCallbacks( + void * inRefCon, + AudioFile_ReadProc inReadFunc, + AudioFile_WriteProc inWriteFunc, + AudioFile_GetSizeProc inGetSizeFunc, + AudioFile_SetSizeProc inSetSizeFunc, + UInt32 inFileType, + const AudioStreamBasicDescription *inFormat, + UInt32 inFlags) +{ + DataSource* dataSource = new Seekable_DataSource(inRefCon, inReadFunc, inWriteFunc, inGetSizeFunc, inSetSizeFunc); + if (!dataSource->CanWrite()) return -54/*permErr*/; + dataSource->SetSize(0); + SetDataSource(dataSource); + SetPermissions(kAudioFileReadWritePermission); + + SetAlignDataWithFillerChunks(!(inFlags & 2 /* kAudioFileFlags_DontPageAlignAudioData */ )); + + OSStatus err = SetDataFormat(inFormat); + if (err) return err; + + return InitializeDataSource(inFormat, inFlags); +} + +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +OSStatus AudioFileObject::DoInitialize( + CFURLRef inFileRef, + const AudioStreamBasicDescription *inFormat, + UInt32 inFlags) +{ + SetURL (inFileRef); + SetPermissions(kAudioFileReadWritePermission); + + SetAlignDataWithFillerChunks(!(inFlags & 2 /* kAudioFileFlags_DontPageAlignAudioData */ )); + + return Initialize(inFileRef, inFormat, inFlags); +} +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +OSStatus AudioFileObject::Initialize( + CFURLRef inFileRef, + const AudioStreamBasicDescription *inFormat, + UInt32 inFlags) +{ + OSStatus err = noErr; + + UInt8 fPath[FILENAME_MAX]; + if (!CFURLGetFileSystemRepresentation (inFileRef, true, fPath, FILENAME_MAX)) + return kAudio_FileNotFoundError; + +#if TARGET_OS_WIN32 + int filePerms = 0; + int flags = O_TRUNC | O_RDWR | O_BINARY; +#else + mode_t filePerms = 0; + int flags = O_TRUNC | O_RDWR; +#endif + + int fileD = open((const char*)fPath, flags, filePerms); + if (fileD < 0) + return AudioFileTranslateErrno(errno); + + err = OpenFile(kAudioFileReadWritePermission, fileD); + FailIf (err != noErr, Bail, "OpenFile failed"); + + // don't need to do this as open has an option to truncate the file +// GetDataSource()->SetSize(0); + + err = SetDataFormat(inFormat); + FailIf (err != noErr, Bail, "SetDataFormat failed"); + + InitializeDataSource(inFormat, inFlags); + +Bail: + return err; +} + +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +OSStatus AudioFileObject::InitializeDataSource(const AudioStreamBasicDescription *inFormat, UInt32 /*inFlags*/) +{ + return noErr; +} + +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +OSStatus AudioFileObject::DoClose() +{ + OSStatus err = UpdateSizeIfNeeded(); + if (err) return err; + + return Close(); +} + +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +OSStatus AudioFileObject::Close() +{ + try { + delete mDataSource; + mDataSource = 0; + } catch (OSStatus err) { + return err; + } catch (...) { + return kAudioFileUnspecifiedError; + } + return noErr; +} + +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +OSStatus AudioFileObject::Optimize() +{ + // default is that nothing needs to be done. This happens to be true for Raw, SD2 and NeXT/Sun types. + SetIsOptimized(true); + return noErr; +} + +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +OSStatus AudioFileObject::DoOptimize() +{ + if (!CanWrite()) return kAudioFilePermissionsError; + + OSStatus err = UpdateSizeIfNeeded(); + if (err) return err; + + if (IsOptimized()) return noErr; + + err = Optimize(); + return err; +} + +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +OSStatus AudioFileObject::UpdateNumBytes(SInt64 inNumBytes) +{ + OSStatus err = noErr; + if (inNumBytes != GetNumBytes()) { + SetNumBytes(inNumBytes); + + // #warning " this will not work for vbr formats" + SetNumPackets(GetNumBytes() / mDataFormat.mBytesPerPacket); + SizeChanged(); + } + return err; +} + +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +OSStatus AudioFileObject::UpdateNumPackets(SInt64 inNumPackets) +{ + OSStatus err = noErr; + if (inNumPackets != GetNumPackets()) { + // sync current state. + SetNeedsSizeUpdate(true); + UpdateSizeIfNeeded(); + SetNumPackets(inNumPackets); + + // #warning " this will not work for vbr formats" + SetNumBytes(GetNumPackets() * mDataFormat.mBytesPerFrame); + SizeChanged(); + } + return err; +} + + +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +OSStatus AudioFileObject::PacketToFrame(SInt64 inPacket, SInt64& outFirstFrameInPacket) +{ + if (mDataFormat.mFramesPerPacket == 0) + { + OSStatus err = ScanForPackets(inPacket+1); // the packet count must be one greater than the packet index + if (err) return err; + + SInt64 packetTableSize = GetPacketTableSize(); + + if (mPacketTable && inPacket >= packetTableSize) + return kAudioFileEndOfFileError; + + CompressedPacketTable* packetTable = GetPacketTable(); + if (!packetTable) + return kAudioFileInvalidPacketOffsetError; + + if (inPacket < 0 || inPacket >= packetTableSize) + return kAudioFileInvalidPacketOffsetError; + + outFirstFrameInPacket = (*packetTable)[(size_t)inPacket].mFrameOffset; + } + else + { + outFirstFrameInPacket = inPacket * mDataFormat.mFramesPerPacket; + } + return noErr; +} + +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +OSStatus AudioFileObject::FrameToPacket(SInt64 inFrame, SInt64& outPacket, UInt32& outFrameOffsetInPacket) +{ + if (mDataFormat.mFramesPerPacket == 0) + { + CompressedPacketTable* packetTable = GetPacketTable(); + if (!packetTable) + return kAudioFileInvalidPacketOffsetError; + + // search packet table + AudioStreamPacketDescriptionExtended pext; + memset(&pext, 0, sizeof(pext)); + pext.mFrameOffset = inFrame; + CompressedPacketTable::iterator iter = std::lower_bound(packetTable->begin(), packetTable->end(), pext); + + if (iter == packetTable->end()) + return kAudioFileInvalidPacketOffsetError; + + if (iter > packetTable->begin()) --iter; + + outPacket = iter - packetTable->begin(); + outFrameOffsetInPacket = (UInt32)(inFrame - iter->mFrameOffset); + } + else + { + outPacket = inFrame / mDataFormat.mFramesPerPacket; + outFrameOffsetInPacket = (UInt32)(inFrame % mDataFormat.mFramesPerPacket); + } + return noErr; +} + +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +OSStatus AudioFileObject::PacketToByte(AudioBytePacketTranslation* abpt) +{ + if (abpt->mPacket < 0) + return kAudioFileInvalidPacketOffsetError; + + if (mDataFormat.mBytesPerPacket == 0) + { + CompressedPacketTable* packetTable = GetPacketTable(); + if (!packetTable) + return kAudioFileInvalidPacketOffsetError; + + if (abpt->mPacket < GetPacketTableSize()) { + abpt->mByte = (*packetTable)[(int)abpt->mPacket].mStartOffset; + abpt->mFlags = 0; + } else { + SInt64 numPackets = packetTable->size(); + if (numPackets < 8) + return 'more' /*kAudioFileStreamError_DataUnavailable*/ ; + + const AudioStreamPacketDescriptionExtended lastPacket = (*packetTable)[numPackets - 1]; + SInt64 bytesReadSoFar = lastPacket.mStartOffset + lastPacket.mDataByteSize; + double averageBytesPerPacket = (double)(bytesReadSoFar - GetDataOffset()) / (double)numPackets; + abpt->mByte = (SInt64)floor((double)abpt->mPacket * averageBytesPerPacket); + abpt->mFlags = kBytePacketTranslationFlag_IsEstimate; + } + } + else + { + abpt->mByte = abpt->mPacket * mDataFormat.mBytesPerPacket; + abpt->mFlags = 0; + } + return noErr; +} + +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +inline bool byte_less_than (const AudioStreamPacketDescriptionExtended& a, const AudioStreamPacketDescriptionExtended& b) +{ + return a.mStartOffset < b.mStartOffset; +} + +OSStatus AudioFileObject::ByteToPacket(AudioBytePacketTranslation* abpt) +{ + if (abpt->mByte < 0) + return kAudioFileInvalidPacketOffsetError; + + if (mDataFormat.mBytesPerPacket == 0) + { + CompressedPacketTable* packetTable = GetPacketTable(); + if (!packetTable) + return kAudioFileInvalidPacketOffsetError; + // search packet table + AudioStreamPacketDescriptionExtended pext; + memset(&pext, 0, sizeof(pext)); + pext.mStartOffset = abpt->mByte; + CompressedPacketTable::iterator iter = std::lower_bound(packetTable->begin(), packetTable->end(), pext, byte_less_than); + + if (iter == packetTable->end()) { + SInt64 numPackets = packetTable->size(); + if (numPackets < 8) + return 'more' /*kAudioFileStreamError_DataUnavailable*/ ; + + const AudioStreamPacketDescriptionExtended lastPacket = (*packetTable)[numPackets - 1]; + SInt64 bytesReadSoFar = lastPacket.mStartOffset + lastPacket.mDataByteSize; + double averageBytesPerPacket = (double)(bytesReadSoFar - GetDataOffset()) / (double)numPackets; + + double fpacket = (double)abpt->mByte / averageBytesPerPacket; + abpt->mPacket = (SInt64)floor(fpacket); + abpt->mByteOffsetInPacket = (UInt32)floor((fpacket - (double)abpt->mPacket) * averageBytesPerPacket); + abpt->mFlags = kBytePacketTranslationFlag_IsEstimate; + + } else { + if (iter > packetTable->begin()) --iter; + abpt->mPacket = iter - packetTable->begin(); + abpt->mByteOffsetInPacket = (UInt32)(abpt->mByte - iter->mStartOffset); + abpt->mFlags = 0; + } + } + else + { + abpt->mPacket = abpt->mByte / mDataFormat.mBytesPerPacket; + abpt->mByteOffsetInPacket = (UInt32)(abpt->mByte % mDataFormat.mBytesPerPacket); + abpt->mFlags = 0; + } + return noErr; +} + + +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +OSStatus AudioFileObject::ReadBytes( + Boolean inUseCache, + SInt64 inStartingByte, + UInt32 *ioNumBytes, + void *outBuffer) +{ + OSStatus err = noErr; + UInt16 mode = SEEK_SET; + SInt64 fileOffset = mDataOffset + inStartingByte; + bool readingPastEnd = false; + + FailWithAction((ioNumBytes == NULL) || (outBuffer == NULL), err = kAudio_ParamError, + Bail, "invalid num bytes parameter"); + + //printf("inStartingByte %lld GetNumBytes %lld\n", inStartingByte, GetNumBytes()); + + if (inStartingByte >= GetNumBytes()) + { + *ioNumBytes = 0; + return kAudioFileEndOfFileError; + } + + if ((fileOffset + *ioNumBytes) > (GetNumBytes() + mDataOffset)) + { + *ioNumBytes = (UInt32)(GetNumBytes() + mDataOffset - fileOffset); + readingPastEnd = true; + } + //printf("fileOffset %lld mDataOffset %lld readingPastEnd %d\n", fileOffset, mDataOffset, readingPastEnd); + + if (!inUseCache) + mode |= kAudioFileNoCacheMask; + + err = GetDataSource()->ReadBytes(mode, fileOffset, *ioNumBytes, outBuffer, ioNumBytes); + + if (readingPastEnd && err == noErr) + err = kAudioFileEndOfFileError; + +Bail: + return err; +} + + +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +OSStatus AudioFileObject::WriteBytes( + Boolean inUseCache, + SInt64 inStartingByte, + UInt32 *ioNumBytes, + const void *inBuffer) +{ + OSStatus err = noErr; + UInt16 mode = SEEK_SET; + bool extendingTheAudioData; + + if (!CanWrite()) return kAudioFilePermissionsError; + + FailWithAction((ioNumBytes == NULL) || (inBuffer == NULL), err = kAudioFileUnspecifiedError, Bail, "invalid parameters"); + + // Do not try to write to a postion greater than 32 bits for some file types + // see if starting byte + ioNumBytes is greater than 32 bits + // if so, see if file type supports this and bail if not + err = IsValidFilePosition(inStartingByte + *ioNumBytes); + FailIf(err != noErr, Bail, "invalid file position"); + + extendingTheAudioData = inStartingByte + *ioNumBytes > GetNumBytes(); + + // if file is not optimized, then do not write data that would overwrite chunks following the sound data chunk + FailWithAction( extendingTheAudioData && !IsOptimized(), + err = kAudioFileNotOptimizedError, Bail, "Can't write more data until the file is optimized"); + + if (!inUseCache) + mode |= kAudioFileNoCacheMask; + + err = GetDataSource()->WriteBytes(mode, mDataOffset + inStartingByte, *ioNumBytes, + inBuffer, ioNumBytes); + + FailIf(err != noErr, Bail, "couldn't write new data"); + + if (extendingTheAudioData) { + SInt64 nuEOF; // Get the total bytes of audio data + SInt64 nuByteTotal; + + err = GetDataSource()->GetSize(nuEOF); + FailIf(err != noErr, Bail, "GetSize failed"); + + nuByteTotal = nuEOF - mDataOffset; + err = UpdateNumBytes(nuByteTotal); + } + +Bail: + return err; +} + +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +OSStatus AudioFileObject::ReadPackets( + Boolean inUseCache, + UInt32 *outNumBytes, + AudioStreamPacketDescription *outPacketDescriptions, + SInt64 inStartingPacket, + UInt32 *ioNumPackets, + void *outBuffer) +{ + // This only works with CBR. To suppport VBR you must override. + OSStatus err = noErr; + + FailWithAction(outBuffer == NULL, err = kAudio_ParamError, Bail, "NULL buffer"); + + FailWithAction((ioNumPackets == NULL) || (*ioNumPackets < 1), err = kAudio_ParamError, Bail, "invalid num packets parameter"); + + { + UInt32 byteCount = *ioNumPackets * mDataFormat.mBytesPerPacket; + SInt64 startingByte = inStartingPacket * mDataFormat.mBytesPerPacket; + + err = ReadBytes (inUseCache, startingByte, &byteCount, outBuffer); + if ((err == noErr) || (err == kAudioFileEndOfFileError)) + { + if (byteCount != (*ioNumPackets * mDataFormat.mBytesPerPacket)) + { + *ioNumPackets = byteCount / mDataFormat.mBytesPerPacket; + byteCount = *ioNumPackets * mDataFormat.mBytesPerPacket; + } + + if (outNumBytes) + *outNumBytes = byteCount; + + if (err == kAudioFileEndOfFileError) + err = noErr; + } + } +Bail: + return err; +} + + +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +OSStatus AudioFileObject::ReadPacketData( + Boolean inUseCache, + UInt32 *ioNumBytes, + AudioStreamPacketDescription *outPacketDescriptions, + SInt64 inStartingPacket, + UInt32 *ioNumPackets, + void *outBuffer) +{ + OSStatus err = noErr; + FailWithAction(ioNumPackets == NULL || *ioNumPackets < 1, err = kAudio_ParamError, Bail, "invalid ioNumPackets parameter"); + FailWithAction(ioNumBytes == NULL || *ioNumBytes < 1, err = kAudio_ParamError, Bail, "invalid ioNumBytes parameter"); + if (mDataFormat.mBytesPerPacket) { + // CBR + FailWithAction(outBuffer == NULL, err = kAudio_ParamError, Bail, "NULL buffer"); + UInt32 maxPackets = *ioNumBytes / mDataFormat.mBytesPerPacket; + if (*ioNumPackets > maxPackets) *ioNumPackets = maxPackets; + + if (outBuffer) { + UInt32 byteCount = *ioNumPackets * mDataFormat.mBytesPerPacket; + SInt64 startingByte = inStartingPacket * mDataFormat.mBytesPerPacket; + err = ReadBytes (inUseCache, startingByte, &byteCount, outBuffer); + if (err == noErr || err == kAudioFileEndOfFileError) { + if (byteCount != (*ioNumPackets * mDataFormat.mBytesPerPacket)) { + *ioNumPackets = byteCount / mDataFormat.mBytesPerPacket; + byteCount = *ioNumPackets * mDataFormat.mBytesPerPacket; + } + *ioNumBytes = byteCount; + } + } + } else { + FailWithAction(outPacketDescriptions == NULL, err = kAudio_ParamError, Bail, "invalid outPacketDescriptions parameter"); + err = ReadPacketDataVBR(inUseCache, ioNumBytes, outPacketDescriptions, inStartingPacket, ioNumPackets, outBuffer); + } +Bail: + return err; +} + +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +OSStatus AudioFileObject::ReadPacketDataVBR( + Boolean inUseCache, + UInt32 *ioNumBytes, + AudioStreamPacketDescription *outPacketDescriptions, + SInt64 inStartingPacket, + UInt32 *ioNumPackets, + void *outBuffer) +{ + OSStatus err = ScanForPackets(inStartingPacket+1); // need to scan packets up to start + if (err && err != kAudioFileEndOfFileError) + return err; + + SInt64 dataOffset = GetDataOffset(); + + CompressedPacketTable* packetTable = GetPacketTable(); + if (!packetTable) + return kAudioFileInvalidFileError; + + SInt64 packetTableSize = GetPacketTableSize(); + + if (inStartingPacket >= packetTableSize) { + *ioNumBytes = 0; + *ioNumPackets = 0; + return kAudioFileEndOfFileError; + } + + if (inStartingPacket + *ioNumPackets <= packetTableSize) { + err = ReadPacketDataVBR_InTable(inUseCache, ioNumBytes, outPacketDescriptions, inStartingPacket, ioNumPackets, outBuffer); + } else { + + AudioStreamPacketDescription firstPacket = (*packetTable)[inStartingPacket]; + SInt64 firstPacketOffset = firstPacket.mStartOffset; + UInt32 bytesRead = *ioNumBytes; + SInt64 fileSize = 0; + GetDataSource()->GetSize(fileSize); + SInt64 remainingBytesInFile = fileSize - firstPacketOffset - dataOffset; + if (bytesRead > remainingBytesInFile) + bytesRead = (UInt32)remainingBytesInFile; + + err = ReadBytes (inUseCache, firstPacketOffset, &bytesRead, outBuffer); + if (err && err != kAudioFileEndOfFileError) { + *ioNumBytes = 0; + *ioNumPackets = 0; + return err; + } + + Buffer_DataSource bufSrc(bytesRead, outBuffer, dataOffset + firstPacketOffset); + + OSStatus scanErr = ScanForPackets(kScanToEnd, &bufSrc, false); + if (scanErr && scanErr != kAudioFileEndOfFileError) + return scanErr; + packetTableSize = packetTable->size(); + + UInt32 numPacketsRead = 0; + UInt32 endOfData = 0; + SInt64 packetNumber = inStartingPacket; + for (; numPacketsRead < *ioNumPackets && packetNumber < packetTableSize; ++numPacketsRead, ++packetNumber) { + AudioStreamPacketDescription curPacket = (*packetTable)[numPacketsRead + inStartingPacket]; + SInt64 curPacketOffset = curPacket.mStartOffset - firstPacketOffset; + SInt64 endOfPacket = curPacketOffset + curPacket.mDataByteSize; + if (endOfPacket > bytesRead) break; + endOfData = (UInt32)endOfPacket; + outPacketDescriptions[numPacketsRead] = curPacket; + outPacketDescriptions[numPacketsRead].mStartOffset = curPacketOffset; + } + + *ioNumBytes = endOfData; + *ioNumPackets = numPacketsRead; + } + return err; +} + + +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +OSStatus AudioFileObject::HowManyPacketsCanBeReadIntoBuffer(UInt32* ioNumBytes, SInt64 inStartingPacket, UInt32 *ioNumPackets) +{ + CompressedPacketTable* packetTable = GetPacketTable(); + SInt64 packetTableSize = GetPacketTableSize(); + + if (inStartingPacket + *ioNumPackets > (SInt64)packetTableSize) { + *ioNumPackets = (UInt32)(packetTableSize - inStartingPacket); + } + + AudioStreamPacketDescription firstPacket = (*packetTable)[inStartingPacket]; + + if (*ioNumBytes < firstPacket.mDataByteSize) { + *ioNumBytes = 0; + *ioNumPackets = 0; + return kAudio_ParamError; + } + + SInt64 lastPacketIndex = inStartingPacket + *ioNumPackets - 1; + if (lastPacketIndex >= packetTableSize) + lastPacketIndex = packetTableSize - 1; + + AudioStreamPacketDescription lastPacket = (*packetTable)[lastPacketIndex]; + + SInt64 readBytes = lastPacket.mStartOffset + lastPacket.mDataByteSize - firstPacket.mStartOffset; + if (readBytes <= *ioNumBytes) { + *ioNumBytes = (UInt32)readBytes; + return noErr; + } + + SInt64 lowBound = inStartingPacket; + SInt64 highBound = lastPacketIndex + 1; + SInt64 okIndex = lowBound; + while (highBound >= lowBound) { + SInt64 tryBound = (lowBound + highBound) >> 1; + if (tryBound > lastPacketIndex) + break; + AudioStreamPacketDescription tryPacket = (*packetTable)[tryBound]; + + SInt64 readBytes = tryPacket.mStartOffset + tryPacket.mDataByteSize - firstPacket.mStartOffset; + + if (readBytes > (SInt64)*ioNumBytes) { + highBound = tryBound - 1; + } else if (readBytes < (SInt64)*ioNumBytes) { + okIndex = tryBound; + lowBound = tryBound + 1; + } else { + okIndex = tryBound; + break; + } + } + + SInt64 numPackets = okIndex - inStartingPacket + 1; + if (numPackets > *ioNumPackets) { + numPackets = *ioNumPackets; + okIndex = inStartingPacket + numPackets - 1; + } + + AudioStreamPacketDescription packet = (*packetTable)[okIndex]; + *ioNumBytes = (UInt32)(packet.mStartOffset + packet.mDataByteSize - firstPacket.mStartOffset); + *ioNumPackets = (UInt32)numPackets; + return noErr; +} + +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + + +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +OSStatus AudioFileObject::ReadPacketDataVBR_InTable( + Boolean inUseCache, + UInt32 *ioNumBytes, + AudioStreamPacketDescription *outPacketDescriptions, + SInt64 inStartingPacket, + UInt32 *ioNumPackets, + void *outBuffer) +{ + CompressedPacketTable* packetTable = GetPacketTable(); + if (!packetTable) + return kAudioFileInvalidFileError; + + OSStatus err = HowManyPacketsCanBeReadIntoBuffer(ioNumBytes, inStartingPacket, ioNumPackets); + if (err) return err; + + AudioStreamPacketDescription firstPacket = (*packetTable)[inStartingPacket]; + SInt64 firstPacketOffset = firstPacket.mStartOffset; + UInt32 bytesRead = *ioNumBytes; + + if (outBuffer) { + err = ReadBytes (inUseCache, firstPacketOffset, &bytesRead, outBuffer); + if (err && err != kAudioFileEndOfFileError) { + *ioNumBytes = 0; + *ioNumPackets = 0; + return err; + } + *ioNumBytes = bytesRead; + } + + // fill out packet descriptions + if (outPacketDescriptions) { + for (UInt32 i = 0; i < *ioNumPackets; i++) { + AudioStreamPacketDescription curPacket = (*packetTable)[i + inStartingPacket]; + outPacketDescriptions[i] = curPacket; + outPacketDescriptions[i].mStartOffset = curPacket.mStartOffset - firstPacketOffset; + } + } + + return err; +} + + +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +OSStatus AudioFileObject::WritePackets( + Boolean inUseCache, + UInt32 inNumBytes, + const AudioStreamPacketDescription *inPacketDescriptions, + SInt64 inStartingPacket, + UInt32 *ioNumPackets, + const void *inBuffer) +{ + // This only works with CBR. To suppport VBR you must override. + OSStatus err = noErr; + + FailWithAction(inStartingPacket > GetNumPackets(), err = kAudioFileInvalidPacketOffsetError, Bail, "write past end"); + FailWithAction((ioNumPackets == NULL) || (inBuffer == NULL), err = kAudioFileUnspecifiedError, Bail, "invalid parameter"); + + { + UInt32 byteCount = *ioNumPackets * mDataFormat.mBytesPerPacket; + SInt64 startingByte = inStartingPacket * mDataFormat.mBytesPerPacket; + + err = WriteBytes(inUseCache, startingByte, &byteCount, inBuffer); + FailIf (err != noErr, Bail, "Write Bytes Failed"); + + if (byteCount != (*ioNumPackets * mDataFormat.mBytesPerPacket)) + *ioNumPackets = byteCount / mDataFormat.mBytesPerPacket; + } +Bail: + return (err); +} + +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +OSStatus AudioFileObject::GetBitRate( UInt32 *outBitRate) +{ + + if (!outBitRate) return kAudioFileUnspecifiedError; + + UInt32 bytesPerPacket = GetDataFormat().mBytesPerPacket; + UInt32 framesPerPacket = GetDataFormat().mFramesPerPacket; + Float64 sampleRate = GetDataFormat().mSampleRate; + const Float64 bitsPerByte = 8.; + + if (bytesPerPacket && framesPerPacket) { + *outBitRate = (UInt32)(bitsPerByte * (Float64)bytesPerPacket * sampleRate / (Float64)framesPerPacket); + } else { + SInt64 numPackets = GetNumPackets(); + SInt64 numBytes = GetNumBytes(); + SInt64 numFrames = 0; + + if (framesPerPacket) { + numFrames = numPackets * framesPerPacket; + } else { + // count frames + CompressedPacketTable* packetTable = GetPacketTable(); + if (packetTable) { + if (packetTable->size() != numPackets) { + return kAudioFileInvalidFileError; + } +#if !TARGET_OS_WIN32 + for (ssize_t i = 0; i < numPackets; i++) +#else + for (int i = 0; i < numPackets; i++) +#endif + { + numFrames += (*packetTable)[i].mVariableFramesInPacket; + } + } else { + return kAudioFileUnsupportedPropertyError; + } + } + + if (numFrames == 0 || (sampleRate == 0.)) { + *outBitRate = 0; + return noErr; + } + Float64 duration = (Float64)numFrames / sampleRate; + *outBitRate = (UInt32)(bitsPerByte * (Float64)numBytes / duration); + } + + return noErr; +} + +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +OSStatus AudioFileObject::GetMagicCookieDataSize( + UInt32 *outDataSize, + UInt32 *isWritable) +{ + if (outDataSize) *outDataSize = 0; + if (isWritable) *isWritable = 0; + return kAudioFileUnsupportedPropertyError; +} + +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +OSStatus AudioFileObject::GetMagicCookieData( + UInt32 *ioDataSize, + void *ioPropertyData) +{ + *ioDataSize = 0; + return kAudioFileUnsupportedPropertyError; +} + +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +OSStatus AudioFileObject::SetMagicCookieData( UInt32 /*inDataSize*/, + const void *inPropertyData) +{ + return kAudioFileInvalidChunkError; +} + +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +OSStatus AudioFileObject::GetMarkerListSize( + UInt32 *outDataSize, + UInt32 *isWritable) +{ + if (outDataSize) *outDataSize = 0; + if (isWritable) *isWritable = 0; + return kAudioFileUnsupportedPropertyError; +} + +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +OSStatus AudioFileObject::GetMarkerList( + UInt32 *ioDataSize, + AudioFileMarkerList* /*ioPropertyData*/) +{ + *ioDataSize = 0; + return kAudioFileUnsupportedPropertyError; +} + +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +OSStatus AudioFileObject::SetMarkerList( UInt32 /*inDataSize*/, + const AudioFileMarkerList* /*inPropertyData*/) +{ + return kAudioFileUnsupportedPropertyError; +} + + +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +OSStatus AudioFileObject::GetRegionListSize( + UInt32 *outDataSize, + UInt32 *isWritable) +{ + if (outDataSize) *outDataSize = 0; + if (isWritable) *isWritable = 0; + return kAudioFileUnsupportedPropertyError; +} + +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +OSStatus AudioFileObject::GetRegionList( + UInt32 *ioDataSize, + AudioFileRegionList *ioPropertyData) +{ + *ioDataSize = 0; + return kAudioFileUnsupportedPropertyError; +} + +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +OSStatus AudioFileObject::SetRegionList( UInt32 /*inDataSize*/, + const AudioFileRegionList* /*inPropertyData*/) +{ + return kAudioFileUnsupportedPropertyError; +} + +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +OSStatus AudioFileObject::GetChannelLayoutSize( + UInt32 *outDataSize, + UInt32 *isWritable) +{ + if (outDataSize) *outDataSize = 0; + if (isWritable) *isWritable = 0; + return kAudioFileUnsupportedPropertyError; +} + +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +OSStatus AudioFileObject::GetChannelLayout( + UInt32 *ioDataSize, + AudioChannelLayout* /*ioPropertyData*/) +{ + *ioDataSize = 0; + return kAudioFileUnsupportedPropertyError; +} + +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +OSStatus AudioFileObject::SetChannelLayout( UInt32 /*inDataSize*/, + const AudioChannelLayout* /*inPropertyData*/) +{ + return kAudioFileUnsupportedPropertyError; +} + +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +OSStatus AudioFileObject::GetInfoDictionarySize( UInt32 *outDataSize, + UInt32 *isWritable) +{ + if (outDataSize) *outDataSize = sizeof(CFDictionaryRef); + if (isWritable) *isWritable = 0; + return noErr; +} + +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +OSStatus AudioFileObject::GetInfoDictionary(CACFDictionary *infoDict) +{ + Float64 fl; + if (GetEstimatedDuration(&fl) == noErr) + return AddDurationToInfoDictionary(infoDict, fl); + + return kAudioFileUnsupportedPropertyError; +} + +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +OSStatus AudioFileObject::SetInfoDictionary(CACFDictionary *infoDict) +{ + return kAudioFileUnsupportedPropertyError; +} + +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +OSStatus AudioFileObject::GetEstimatedDuration(Float64* duration) +{ + // calculate duration + AudioStreamBasicDescription ASBD = GetDataFormat(); + + *duration = (ASBD.mFramesPerPacket != 0) ? (GetNumPackets() * ASBD.mFramesPerPacket) / ASBD.mSampleRate : 0.0; + + /* + For now, assume that any ASBD that has zero in the frames per packet field has been subclassed for this + method. i.e. A CAF file has a frame count in one of it's chunks. + + MP3 has been subclassed because it guesstimates a duration so the entire file does not + need to be parsed in order to calculate the total frames. + */ + + return noErr; + +} + +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +OSStatus AudioFileObject::GetPropertyInfo ( + AudioFilePropertyID inPropertyID, + UInt32 *outDataSize, + UInt32 *isWritable) +{ + OSStatus err = noErr; + UInt32 writable = 0; + + switch (inPropertyID) + { + case kAudioFilePropertyDeferSizeUpdates : + if (outDataSize) *outDataSize = sizeof(UInt32); + writable = 1; + break; + + case kAudioFilePropertyFileFormat: + if (outDataSize) *outDataSize = sizeof(UInt32); + writable = 0; + break; + + case kAudioFilePropertyDataFormat: + if (outDataSize) *outDataSize = sizeof(AudioStreamBasicDescription); + writable = 1; + break; + + case kAudioFilePropertyFormatList: + err = GetFormatListInfo(*outDataSize, writable); + break; + + case kAudioFilePropertyPacketSizeUpperBound: + case kAudioFilePropertyIsOptimized: + case kAudioFilePropertyMaximumPacketSize: + if (outDataSize) *outDataSize = sizeof(UInt32); + writable = 0; + break; + + case kAudioFilePropertyAudioDataByteCount: + case kAudioFilePropertyAudioDataPacketCount: + writable = 1; + if (outDataSize) *outDataSize = sizeof(SInt64); + break; + + case kAudioFilePropertyDataOffset: + writable = 0; + if (outDataSize) *outDataSize = sizeof(SInt64); + break; + + case kAudioFilePropertyBitRate: + writable = 0; + if (outDataSize) *outDataSize = sizeof(UInt32); + break; + + case kAudioFilePropertyMagicCookieData: + err = GetMagicCookieDataSize(outDataSize, &writable); + break; + + case kAudioFilePropertyMarkerList : + err = GetMarkerListSize(outDataSize, &writable); + break; + + case kAudioFilePropertyRegionList : + err = GetRegionListSize(outDataSize, &writable); + break; + + case kAudioFilePropertyChannelLayout : + err = GetChannelLayoutSize(outDataSize, &writable); + break; + + case kAudioFilePropertyPacketToFrame : + case kAudioFilePropertyFrameToPacket : + if (outDataSize) *outDataSize = sizeof(AudioFramePacketTranslation); + writable = 0; + break; + + case kAudioFilePropertyPacketToByte : + case kAudioFilePropertyByteToPacket : + if (outDataSize) *outDataSize = sizeof(AudioBytePacketTranslation); + writable = 0; + break; + + case kAudioFilePropertyInfoDictionary : + err = GetInfoDictionarySize(outDataSize, &writable); + break; + + case kTEMPAudioFilePropertySoundCheckDictionary : + err = GetSoundCheckDictionarySize(outDataSize, &writable); + break; + + case kTEMPAudioFilePropertyGenerateLoudnessInfo : + err = GetLoudnessInfoSize(outDataSize, &writable); + writable = 0; + break; + + case kTEMPAudioFilePropertyLoudnessInfo : + err = GetLoudnessInfoSize(outDataSize, &writable); + break; + + case kAudioFilePropertyEstimatedDuration : + if (outDataSize) *outDataSize = sizeof(Float64); + writable = 0; + break; + + case 'LYRC': + if (outDataSize) *outDataSize = sizeof(CFStringRef); + if (isWritable) *isWritable = 0; + break; + + case 'eof?': + if (outDataSize) *outDataSize = sizeof(UInt32); + if (isWritable) *isWritable = 0; + break; + + case 'sbtd' /*kAudioFilePropertySourceBitDepth*/ : + if (outDataSize) *outDataSize = sizeof(SInt32); + if (isWritable) *isWritable = CanWrite(); + break; + + default: + writable = 0; + err = kAudioFileUnsupportedPropertyError; + break; + } + + if (isWritable) + *isWritable = writable; + return (err); +} + +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +OSStatus AudioFileObject::GetProperty( + AudioFilePropertyID inPropertyID, + UInt32 *ioDataSize, + void *ioPropertyData) +{ + OSStatus err = noErr; + UInt32 neededSize; + UInt32 writable; + + switch (inPropertyID) + { + case kAudioFilePropertyFileFormat: + FailWithAction(*ioDataSize != sizeof(UInt32), + err = kAudioFileBadPropertySizeError, Bail, "inDataSize is wrong"); + + *(UInt32 *) ioPropertyData = GetFileType(); + break; + + case kAudioFilePropertyFormatList: + err = GetFormatList(*ioDataSize, (AudioFormatListItem*)ioPropertyData); + break; + + case kAudioFilePropertyDataFormat: + FailWithAction(*ioDataSize != sizeof(AudioStreamBasicDescription), + err = kAudioFileBadPropertySizeError, Bail, "inDataSize is wrong"); + + memcpy(ioPropertyData, &mDataFormat, sizeof(AudioStreamBasicDescription)); + break; + case kAudioFilePropertyDataOffset: + FailWithAction(*ioDataSize != sizeof(SInt64), + err = kAudioFileBadPropertySizeError, Bail, "inDataSize is wrong"); + *(SInt64 *) ioPropertyData = mDataOffset; + break; + case kAudioFilePropertyIsOptimized: + FailWithAction(*ioDataSize != sizeof(UInt32), + err = kAudioFileBadPropertySizeError, Bail, "inDataSize is wrong"); + *(UInt32 *) ioPropertyData = mIsOptimized; + break; + + case kAudioFilePropertyAudioDataByteCount: + FailWithAction(*ioDataSize != sizeof(SInt64), + err = kAudioFileBadPropertySizeError, Bail, "inDataSize is wrong"); + *(SInt64 *)ioPropertyData = GetNumBytes(); + break; + + case kAudioFilePropertyAudioDataPacketCount: + FailWithAction(*ioDataSize != sizeof(SInt64), + err = kAudioFileBadPropertySizeError, Bail, "inDataSize is wrong"); + *(SInt64 *)ioPropertyData = GetNumPackets(); + break; + + case kAudioFilePropertyPacketSizeUpperBound: + FailWithAction(*ioDataSize != sizeof(UInt32), + err = kAudioFileBadPropertySizeError, Bail, "inDataSize is wrong"); + *(UInt32 *)ioPropertyData = GetPacketSizeUpperBound(); + break; + + case kAudioFilePropertyMaximumPacketSize: + FailWithAction(*ioDataSize != sizeof(UInt32), + err = kAudioFileBadPropertySizeError, Bail, "inDataSize is wrong"); + *(UInt32 *)ioPropertyData = FindMaximumPacketSize(); + break; + + + case kAudioFilePropertyBitRate: + FailWithAction(*ioDataSize != sizeof(UInt32), + err = kAudioFileBadPropertySizeError, Bail, "inDataSize is wrong"); + err = GetBitRate((UInt32*)ioPropertyData); + break; + + case kAudioFilePropertyMagicCookieData: + + err = GetMagicCookieData(ioDataSize, ioPropertyData); + break; + + case kAudioFilePropertyMarkerList : + err = GetMarkerList(ioDataSize, static_cast<AudioFileMarkerList*>(ioPropertyData)); + break; + + case kAudioFilePropertyRegionList : + memset(ioPropertyData, 0, *ioDataSize); + err = GetRegionList(ioDataSize, static_cast<AudioFileRegionList*>(ioPropertyData)); + break; + + case kAudioFilePropertyChannelLayout : + err = GetChannelLayoutSize(&neededSize, &writable); + FailIf(err, Bail, "GetChannelLayoutSize failed"); + FailWithAction(*ioDataSize != neededSize, err = kAudioFileBadPropertySizeError, Bail, "inDataSize is wrong"); + + err = GetChannelLayout(ioDataSize, static_cast<AudioChannelLayout*>(ioPropertyData)); + break; + + case kAudioFilePropertyDeferSizeUpdates : + FailWithAction(*ioDataSize != sizeof(UInt32), + err = kAudioFileBadPropertySizeError, Bail, "inDataSize is wrong"); + + *(UInt32 *) ioPropertyData = DeferSizeUpdates(); + break; + + case kAudioFilePropertyPacketToFrame : + { + FailWithAction(*ioDataSize != sizeof(AudioFramePacketTranslation), + err = kAudioFileBadPropertySizeError, Bail, "inDataSize is wrong"); + + AudioFramePacketTranslation* afpt = (AudioFramePacketTranslation*)ioPropertyData; + err = PacketToFrame(afpt->mPacket, afpt->mFrame); + break; + } + case kAudioFilePropertyFrameToPacket : + { + FailWithAction(*ioDataSize != sizeof(AudioFramePacketTranslation), + err = kAudioFileBadPropertySizeError, Bail, "inDataSize is wrong"); + + AudioFramePacketTranslation* afpt = (AudioFramePacketTranslation*)ioPropertyData; + err = FrameToPacket(afpt->mFrame, afpt->mPacket, afpt->mFrameOffsetInPacket); + break; + } + + case kAudioFilePropertyPacketToByte : + { + FailWithAction(*ioDataSize != sizeof(AudioBytePacketTranslation), + err = kAudioFileBadPropertySizeError, Bail, "inDataSize is wrong"); + + AudioBytePacketTranslation* abpt = (AudioBytePacketTranslation*)ioPropertyData; + err = PacketToByte(abpt); + break; + } + case kAudioFilePropertyByteToPacket : + { + FailWithAction(*ioDataSize != sizeof(AudioBytePacketTranslation), + err = kAudioFileBadPropertySizeError, Bail, "inDataSize is wrong"); + + AudioBytePacketTranslation* abpt = (AudioBytePacketTranslation*)ioPropertyData; + err = ByteToPacket(abpt); + break; + } + + case kAudioFilePropertyInfoDictionary : + { + FailWithAction(*ioDataSize != sizeof(CFDictionaryRef), + err = kAudioFileBadPropertySizeError, Bail, "inDataSize is wrong"); + + CACFDictionary afInfoDictionary(true); + + err = GetInfoDictionary(&afInfoDictionary); + + if (!err) + { + *(CFMutableDictionaryRef *)ioPropertyData = afInfoDictionary.CopyCFMutableDictionary(); + } + break; + } + + case kTEMPAudioFilePropertySoundCheckDictionary : + { + FailWithAction(*ioDataSize != sizeof(CFDictionaryRef), + err = kAudioFileBadPropertySizeError, Bail, "inDataSize is wrong"); + + CACFDictionary afInfoDictionary(true); + + err = GetSoundCheckDictionary(&afInfoDictionary); + if (err) { + OSStatus err2 = GetSoundCheckDictionaryFromLoudnessInfo(&afInfoDictionary); + if (err2 == noErr) err = noErr; // else report original error from GetSoundCheckDictionary. + } + + if (!err) + { + *(CFMutableDictionaryRef *)ioPropertyData = afInfoDictionary.CopyCFMutableDictionary(); + } + break; + } + + case kTEMPAudioFilePropertyLoudnessInfo : + { + FailWithAction(*ioDataSize != sizeof(CFDictionaryRef), + err = kAudioFileBadPropertySizeError, Bail, "inDataSize is wrong"); + + CACFDictionary afInfoDictionary(true); + + err = GetLoudnessInfo(&afInfoDictionary); + if (err) { + OSStatus err2 = GetLoudnessInfoFromSoundCheckDictionary(&afInfoDictionary); + if (err2 == noErr) err = noErr; // else report original error from GetLoudnessInfo. + } + + if (!err) + { + *(CFMutableDictionaryRef *)ioPropertyData = afInfoDictionary.CopyCFMutableDictionary(); + } + break; + } + + case kTEMPAudioFilePropertyGenerateLoudnessInfo : + { + FailWithAction(*ioDataSize != sizeof(CFDictionaryRef), + err = kAudioFileBadPropertySizeError, Bail, "inDataSize is wrong"); + + CACFDictionary afInfoDictionary(true); + + err = GenerateLoudnessInfo(&afInfoDictionary); + + if (!err) + { + *(CFMutableDictionaryRef *)ioPropertyData = afInfoDictionary.CopyCFMutableDictionary(); + } + break; + } + + case kAudioFilePropertyEstimatedDuration : + { + FailWithAction(*ioDataSize != sizeof(Float64), + err = kAudioFileBadPropertySizeError, Bail, "inDataSize is wrong"); + + err = GetEstimatedDuration((Float64*)ioPropertyData); + break; + } + + case 'LYRC' : + if (*ioDataSize < sizeof(CFStringRef)) + return kAudioFileBadPropertySizeError; + + *ioDataSize = sizeof(CFStringRef); + err = GetLyrics((CFStringRef*) ioPropertyData); + break; + + case 'eof?' : + { + if (*ioDataSize != sizeof(UInt32)) + return kAudioFileBadPropertySizeError; + + SInt64 pos; + err = GetDataSource()->GetPos(pos); + if (err) break; + + SInt64 endOfData = GetDataOffset() + GetNumBytes(); + *(UInt32*)ioPropertyData = pos >= endOfData; + + break; + } + case 'sbtd' /*kAudioFilePropertySourceBitDepth*/ : + { + if (*ioDataSize != sizeof(SInt32)) + return kAudioFileBadPropertySizeError; + + SInt32 outValue = 0; + err = GetSourceBitDepth(outValue); + if ((err || outValue == 0) && GetDataFormat().mFormatID == kAudioFormatLinearPCM) { + // if there was no stored source bit depth, and this file is LPCM, then report this file's bit depth. + err = noErr; + outValue = GetDataFormat().mBitsPerChannel; + if (GetDataFormat().mFormatFlags & kAudioFormatFlagIsFloat) + outValue = -outValue; + } else if (err) + break; + + *(SInt32 *) ioPropertyData = outValue; + + break; + } + default: + err = kAudioFileUnsupportedPropertyError; + break; + } + +Bail: + return err; +} + +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +OSStatus AudioFileObject::SetProperty( + AudioFilePropertyID inPropertyID, + UInt32 inDataSize, + const void *inPropertyData) +{ + OSStatus err = noErr; + + switch (inPropertyID) + { + case kAudioFilePropertyDataFormat: + FailWithAction(inDataSize != sizeof(AudioStreamBasicDescription), + err = kAudioFileBadPropertySizeError, Bail, "Incorrect data size"); + err = UpdateDataFormat((AudioStreamBasicDescription *) inPropertyData); + break; + case kAudioFilePropertyFormatList: + err = SetFormatList(inDataSize, (AudioFormatListItem*)inPropertyData); + break; + + case kAudioFilePropertyAudioDataByteCount: { + FailWithAction(inDataSize != sizeof(SInt64), err = kAudioFileBadPropertySizeError, Bail, "Incorrect data size"); + SInt64 numBytes = *(SInt64 *) inPropertyData; + if (numBytes > GetNumBytes()) { + // can't use this to increase data size. + return kAudioFileOperationNotSupportedError; + } + UInt32 saveDefer = DeferSizeUpdates(); + SetDeferSizeUpdates(0); // force an update. + err = UpdateNumBytes(numBytes); + SetDeferSizeUpdates(saveDefer); + } break; + + case kAudioFilePropertyAudioDataPacketCount: { + SInt64 numPackets = *(SInt64 *) inPropertyData; + if (numPackets > GetNumPackets()) { + // can't use this to increase data size. + return kAudioFileOperationNotSupportedError; + } + err = UpdateNumPackets(numPackets); + } break; + + case kAudioFilePropertyMagicCookieData: + err = SetMagicCookieData(inDataSize, inPropertyData); + break; + + + case kAudioFilePropertyMarkerList : + err = SetMarkerList(inDataSize, static_cast<const AudioFileMarkerList*>(inPropertyData)); + break; + + case kAudioFilePropertyRegionList : + err = SetRegionList(inDataSize, static_cast<const AudioFileRegionList*>(inPropertyData)); + break; + + case kAudioFilePropertyChannelLayout : + err = SetChannelLayout(inDataSize, static_cast<const AudioChannelLayout*>(inPropertyData)); + break; + + case kAudioFilePropertyDeferSizeUpdates : + FailWithAction(inDataSize != sizeof(UInt32), + err = kAudioFileBadPropertySizeError, Bail, "inDataSize is wrong"); + SetDeferSizeUpdates(*(UInt32 *) inPropertyData); + break; + + case kAudioFilePropertyInfoDictionary : + { + FailWithAction(inDataSize != sizeof(CFDictionaryRef), + err = kAudioFileBadPropertySizeError, Bail, "inDataSize is wrong"); + + // pass the SetInfoDictionary a CACFDictionary object made with the provided CFDictionaryRef + // Let the caller release their own CFObject so pass false for th erelease parameter + CACFDictionary afInfoDictionary(*(CFDictionaryRef *)inPropertyData, false); + err = SetInfoDictionary(&afInfoDictionary); + + break; + } + + case kTEMPAudioFilePropertySoundCheckDictionary : + { + FailWithAction(inDataSize != sizeof(CFDictionaryRef), + err = kAudioFileBadPropertySizeError, Bail, "inDataSize is wrong"); + + // pass the SetInfoDictionary a CACFDictionary object made with the provided CFDictionaryRef + // Let the caller release their own CFObject so pass false for the release parameter + CACFDictionary afInfoDictionary(*(CFDictionaryRef *)inPropertyData, false); + err = SetSoundCheckDictionary(&afInfoDictionary); + + break; + } + + case kTEMPAudioFilePropertyLoudnessInfo : + { + FailWithAction(inDataSize != sizeof(CFDictionaryRef), + err = kAudioFileBadPropertySizeError, Bail, "inDataSize is wrong"); + + // pass the SetInfoDictionary a CACFDictionary object made with the provided CFDictionaryRef + // Let the caller release their own CFObject so pass false for the release parameter + CACFDictionary afInfoDictionary(*(CFDictionaryRef *)inPropertyData, false); + err = SetLoudnessInfo(&afInfoDictionary); + + break; + } + + case 'sbtd' /*kAudioFilePropertySourceBitDepth*/ : + { + FailWithAction(inDataSize != sizeof(SInt32), + err = kAudioFileBadPropertySizeError, Bail, "inDataSize is wrong"); + + SInt32 inValue = *(SInt32 *)inPropertyData; + err = SetSourceBitDepth(inValue); + + break; + } + + default: + err = kAudioFileUnsupportedPropertyError; + break; + } + +Bail: + return err; +} + + +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +OSStatus AudioFileObject::SetDataFormat(const AudioStreamBasicDescription* inStreamFormat) +{ + OSStatus err = noErr; + + if (!IsDataFormatValid(inStreamFormat)) + return kAudioFileUnsupportedDataFormatError; + + if (!IsDataFormatSupported(inStreamFormat)) + return kAudioFileUnsupportedDataFormatError; + + UInt32 prevBytesPerPacket = mDataFormat.mBytesPerPacket; + + mDataFormat = *inStreamFormat; + + // if CBR and bytes per packet changes, we need to change the number of packets we think we have. + if (mDataFormat.mBytesPerPacket && mDataFormat.mBytesPerPacket != prevBytesPerPacket) + { + SInt64 numPackets = GetNumBytes() / mDataFormat.mBytesPerPacket; + SetNumPackets(numPackets); + SetMaximumPacketSize(mDataFormat.mBytesPerPacket); + + if (!mFirstSetFormat) + SizeChanged(); + } + + mFirstSetFormat = false; + + return err; +} + +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +OSStatus AudioFileObject::GetFormatListInfo( UInt32 &outDataSize, + UInt32 &outWritable) +{ + // default implementation is to just return the data format + outDataSize = sizeof(AudioFormatListItem); + outWritable = false; + return noErr; +} + +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +OSStatus AudioFileObject::GetFormatList( UInt32 &ioDataSize, + AudioFormatListItem *ioPropertyData) +{ + // default implementation is to just return the data format + if (ioDataSize < sizeof(AudioFormatListItem)) + return kAudioFileBadPropertySizeError; + + AudioFormatListItem afli; + afli.mASBD = mDataFormat; + AudioChannelLayoutTag layoutTag = /*kAudioChannelLayoutTag_Unknown*/ 0xFFFF0000 | mDataFormat.mChannelsPerFrame; + UInt32 layoutSize, isWritable; + OSStatus err = GetChannelLayoutSize(&layoutSize, &isWritable); + if (err == noErr) + { + CAAutoFree<AudioChannelLayout> layout; + layout.allocBytes(layoutSize); + err = GetChannelLayout(&layoutSize, layout()); + if (err == noErr) { + layoutTag = layout->mChannelLayoutTag; + } + } + afli.mChannelLayoutTag = layoutTag; + + memcpy(ioPropertyData, &afli, sizeof(AudioFormatListItem)); + + ioDataSize = sizeof(AudioFormatListItem); + return noErr; +} + +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +OSStatus AudioFileObject::SetFormatList( UInt32 inDataSize, + const AudioFormatListItem *inPropertyData) +{ + return kAudioFileOperationNotSupportedError; +} + +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +OSStatus AudioFileObject::UpdateDataFormat(const AudioStreamBasicDescription* inStreamFormat) +{ + return SetDataFormat(inStreamFormat); +} + + +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Boolean AudioFileObject::IsDataFormatValid(AudioStreamBasicDescription const* inDesc) +{ + if (inDesc->mSampleRate < 0.) + return false; + + if (inDesc->mSampleRate > 3e6) + return false; + + if (inDesc->mChannelsPerFrame < 1 || inDesc->mChannelsPerFrame > 0x000FFFFF) + return false; + + if (inDesc->mFormatID == kAudioFormatLinearPCM) + { + if (inDesc->mBitsPerChannel < 1 || inDesc->mBitsPerChannel > 64) + return false; + + if (inDesc->mFramesPerPacket != 1) + return false; + + if (inDesc->mBytesPerPacket == 0) + return false; + + if (inDesc->mBytesPerFrame != inDesc->mBytesPerPacket) + return false; + + // [3605260] we assume here that a packet is an integer number of frames. + UInt32 minimumBytesPerPacket = (inDesc->mBitsPerChannel * inDesc->mChannelsPerFrame + 7) / 8; + if (inDesc->mBytesPerPacket < minimumBytesPerPacket) + return false; + } + return true; +} + +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +void AudioFileObject::SetDataSource(DataSource* inDataSource) +{ + if (mDataSource != inDataSource) { + delete mDataSource; + mDataSource = inDataSource; + } +} + +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +void AudioFileObject::SetURL (CFURLRef inURL) +{ + if (mFileRef == inURL) return; + if (inURL) CFRetain (inURL); + if (mFileRef) CFRelease(mFileRef); + mFileRef = inURL; +} + +OSStatus AudioFileObject::OpenFile(SInt8 inPermissions, int inFD) +{ + OSStatus err = noErr; + + SetDataSource(new Cached_DataSource(new UnixFile_DataSource(inFD, inPermissions, true))); + + mFileD = inFD; + SetPermissions (inPermissions); + + return err; +} + +OSStatus AudioFileObject::CreateDataFile (CFURLRef inFileRef, int &outFileD) +{ + UInt8 fPath[FILENAME_MAX]; + if (!CFURLGetFileSystemRepresentation (inFileRef, true, fPath, FILENAME_MAX)) + return kAudio_FileNotFoundError; + + struct stat stbuf; + if (stat ((const char*)fPath, &stbuf) == 0) + return kAudioFilePermissionsError; + +#if TARGET_OS_WIN32 + int filePerms = S_IREAD | S_IWRITE; + int flags = O_CREAT | O_EXCL | O_RDWR | O_BINARY; +#else + mode_t filePerms = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; + int flags = O_CREAT | O_EXCL | O_RDWR; +#endif + outFileD = open((const char*)fPath, flags, filePerms); + if (outFileD < 0) + return AudioFileTranslateErrno(errno); + + return noErr; +} + +OSStatus AudioFileObject::AddDurationToInfoDictionary(CACFDictionary *infoDict, Float64 &inDuration) +{ +#if !TARGET_OS_WIN32 + CFLocaleRef currentLocale = CFLocaleGetSystem(); + CFNumberFormatterRef numberFormatter = NULL; + numberFormatter = CFNumberFormatterCreate(kCFAllocatorDefault, currentLocale, kCFNumberFormatterDecimalStyle); + CFStringRef cfStr = CFNumberFormatterCreateStringWithValue( kCFAllocatorDefault, numberFormatter, kCFNumberFloat64Type, &inDuration); + if (cfStr) + { + if (CFStringGetLength(cfStr) != 0) + infoDict->AddString(CFSTR(kAFInfoDictionary_ApproximateDurationInSeconds), cfStr); + CFRelease(cfStr); + } + CFRelease(numberFormatter); +#endif + return noErr; +} + +OSStatus AudioFileObject::SizeChanged() +{ + OSStatus err = noErr; + if (mPermissions & kAudioFileWritePermission) + { + if (DeferSizeUpdates()) + SetNeedsSizeUpdate(true); + else + err = UpdateSize(); + } + return err; +} + +OSStatus AudioFileObject::UpdateSizeIfNeeded() +{ + if (GetNeedsSizeUpdate()) + { + OSStatus err = UpdateSize(); + if (err) return err; + SetNeedsSizeUpdate(false); + } + return noErr; +} + +OSStatus AudioFileObject::CountUserData( UInt32 /*inUserDataID*/, + UInt32* /*outNumberItems*/) +{ + return kAudioFileOperationNotSupportedError; +} + +OSStatus AudioFileObject::GetUserDataSize( UInt32 /*inUserDataID*/, + UInt32 /*inIndex*/, + UInt32* /*outDataSize*/) +{ + return kAudioFileOperationNotSupportedError; +} + +OSStatus AudioFileObject::GetUserData( UInt32 /*inUserDataID*/, + UInt32 /*inIndex*/, + UInt32* /*ioDataSize*/, + void* /*ioUserData*/) +{ + return kAudioFileOperationNotSupportedError; +} + +OSStatus AudioFileObject::SetUserData( UInt32 /*inUserDataID*/, + UInt32 /*inIndex*/, + UInt32 /*inDataSize*/, + const void* /*inUserData*/) +{ + return kAudioFileOperationNotSupportedError; +} + +OSStatus AudioFileObject::RemoveUserData( UInt32 /*inUserDataID*/, + UInt32 /*inIndex*/) +{ + return kAudioFileOperationNotSupportedError; +} + +OSStatus AudioFileObject::MoveData(SInt64 fromPos, SInt64 toPos, SInt64 size) +{ + if (fromPos == toPos) + return noErr; + + OSStatus err = noErr; + CAAutoFree<char> audioData(kCopySoundDataBufferSize, true); + + SInt64 bytesRemaining = size; + if (fromPos < toPos) { + while (bytesRemaining > 0) + { + // read from old file + UInt32 byteCount; + SInt64 count = (bytesRemaining < kCopySoundDataBufferSize) ? bytesRemaining : kCopySoundDataBufferSize; + err = GetDataSource()->ReadBytes(SEEK_SET, fromPos+(bytesRemaining-count), (UInt32)count, audioData(), &byteCount); + FailIf (err != noErr, Bail, "MoveData ReadBytes failed"); + + err = GetDataSource()->WriteBytes(SEEK_SET, toPos+(bytesRemaining-count), (UInt32)count, audioData(), &byteCount); + FailIf (err != noErr, Bail, "WriteBytes failed"); + + bytesRemaining -= count; + } + } else { + while (bytesRemaining > 0) + { + // read from old file + UInt32 byteCount; + SInt64 count = (bytesRemaining < kCopySoundDataBufferSize) ? bytesRemaining : kCopySoundDataBufferSize; + err = GetDataSource()->ReadBytes(SEEK_SET, fromPos+(size - bytesRemaining), (UInt32)count, audioData(), &byteCount); + FailIf (err != noErr, Bail, "MoveData ReadBytes failed"); + + err = GetDataSource()->WriteBytes(SEEK_SET, toPos+(size - bytesRemaining), (UInt32)count, audioData(), &byteCount); + FailIf (err != noErr, Bail, "WriteBytes failed"); + + bytesRemaining -= count; + } + } + +Bail: + return err; +} + +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + diff --git a/libs/appleutility/CoreAudio/AudioFile/AFPublic/AudioFileObject.h b/libs/appleutility/CoreAudio/AudioFile/AFPublic/AudioFileObject.h new file mode 100644 index 0000000000..6d7c868976 --- /dev/null +++ b/libs/appleutility/CoreAudio/AudioFile/AFPublic/AudioFileObject.h @@ -0,0 +1,667 @@ +/* + File: AudioFileObject.h + Abstract: Part of CoreAudio Utility Classes + Version: 1.1 + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple + 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 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. + + Copyright (C) 2014 Apple Inc. All Rights Reserved. + +*/ +#ifndef _AudioFileObject_H_ +#define _AudioFileObject_H_ + +#include <TargetConditionals.h> + +#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__) + #include <CoreAudio/CoreAudioTypes.h> + #include <AudioToolbox/AudioFile.h> + #include <AudioToolbox/AudioFormat.h> +#else + #include "CoreAudioTypes.h" + #include "AudioFile.h" + #include "AudioFormat.h" +#endif + +#include "CompressedPacketTable.h" +#include "CACFDictionary.h" +#include "DataSource.h" +#include <vector> +#include <fcntl.h> + +#if TARGET_OS_WIN32 +#include <io.h> +#endif + +/* + These are structs defined in 10.5. They are included here for compatibility with sources +*/ +#if COREAUDIOTYPES_VERSION < 1050 + +struct AudioFormatListItem +{ + AudioStreamBasicDescription mASBD; + AudioChannelLayoutTag mChannelLayoutTag; +}; +typedef struct AudioFormatListItem AudioFormatListItem; + +struct AudioFormatInfo +{ + AudioStreamBasicDescription mASBD; + const void* mMagicCookie; + UInt32 mMagicCookieSize; +}; +typedef struct AudioFormatInfo AudioFormatInfo; + +enum { + + kAudioFormatProperty_FormatList = 'flst', + // Returns a list of AudioFormatListItem structs describing the audio formats contained within the compressed bit stream + // as described by the magic cookie. + // The specifier is an AudioFormatInfo struct. At a minimum formatID member of the ASBD struct must filled in. Other fields + // may be filled in. + + kAudioFormatProperty_OutputFormatList = 'ofls', + // Returns a list of AudioFormatListItem structs describing the audio formats which may be obtained by decoding the format + // described by the specifier. + // The specifier is an AudioFormatInfo struct. At a minimum formatID member of the ASBD struct must filled in. Other fields + // may be filled in. If there is no magic cookie, then the number of channels and sample rate should be filled in. + +}; + +enum { + kAudioFilePropertyPacketSizeUpperBound = 'pkub', + kAudioFilePropertyFormatList = 'flst', + kAudioFilePropertyEstimatedDuration = 'edur', + kAudioFilePropertyBitRate = 'brat' +}; + +enum { + kAudioFileCreateURLSelect = 0x0019, + kAudioFileOpenURLSelect = 0x001A, + kAudioFileFileDataIsThisFormatSelect = 0x001B +}; +#endif + +enum { + kTEMPAudioFilePropertySoundCheckDictionary = 'scdc', + kTEMPAudioFilePropertyLoudnessInfo = 'loud', + kTEMPAudioFilePropertyGenerateLoudnessInfo = 'glou' +}; + +const UInt32 kCopySoundDataBufferSize = 1024 * 1024; + +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// some files encode these as upper case +enum { + kUpperCase_IMACompression = 'IMA4', /*IMA 4:1*/ + kUpperCase_ULawCompression = 'ULAW', /*µLaw 2:1*/ + kUpperCase_ALawCompression = 'ALAW', /*aLaw 2:1*/ + + kUpperCase_Float32 = 'FL32', + kUpperCase_Float64 = 'FL64' +}; + +enum +{ + // in what header is this defined? what is it? + kGSM = 'agsm', + kUpperCase_GSM = 'GSM ' +}; + +#define kPackedBESInt (kLinearPCMFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsBigEndian | kLinearPCMFormatFlagIsPacked) +#define kPackedLESInt (kLinearPCMFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsPacked) +#define kPackedBEFloat (kLinearPCMFormatFlagIsFloat | kLinearPCMFormatFlagIsBigEndian | kLinearPCMFormatFlagIsPacked) +#define kPackedLEFloat (kLinearPCMFormatFlagIsFloat | kLinearPCMFormatFlagIsPacked) + +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +inline int TransformPerm_FS_O (SInt8 inPerm) +{ + switch (inPerm) { + case kAudioFileReadPermission: return O_RDONLY; + case kAudioFileWritePermission: return O_WRONLY; + case kAudioFileReadWritePermission: return O_RDWR; + } + return O_RDONLY; +} + +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +#pragma mark "File Error Handling" +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +#include <errno.h> +#include <CoreAudio/CoreAudioTypes.h> + +inline OSErr AudioFileTranslateErrno(int err) +{ + switch (err) { +#if !TARGET_OS_WIN32 + case ENFILE: +#endif + case EMFILE: + return -42 /* kAudio_TooManyFilesOpenError */; +#if !TARGET_OS_WIN32 + case EPERM: + case EROFS: +#endif + case EACCES: + case EEXIST: + return -54 /* kAudio_FilePermissionError */; +#if !TARGET_OS_WIN32 + case EMLINK: + return (OSErr)'!pth' /* kAudio_BadFilePathError */; + case ENOTDIR: + case ELOOP: +#endif + case ENOENT: + default: + return (OSErr)kAudioFileUnspecifiedError; + } +} + +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +class AudioFileObject +{ +protected: + +private: + SInt64 mNumBytes; // total bytes of audio data in the audio file + SInt64 mNumPackets; // total frames of audio data in the audio file + AudioStreamBasicDescription mDataFormat; // format of the audio data + SInt64 mDataOffset; // position if the file where audio data begins + UInt32 mIsOptimized; // 1 if there is nothing in the file following the audio data, 0 if there is + UInt32 mFileType; // file type of the audio file (i.e. AIFF, WAVE, etc.) + CFURLRef mFileRef; // URL of the file passed to AudioFileOpen or AudioFileCreate + int mFileD; // Ref num of the file after opening within Audio File + SInt8 mPermissions; // file permissions indicated by the caller, passed by AudioFileOpen or set with SetProperty function + Boolean mIsInitialized; // has the AudioFileObject for this file been intialized? + DataSource *mDataSource; + UInt32 mMaximumPacketSize; + CompressedPacketTable *mPacketTable; + UInt32 mDeferSizeUpdates; + Boolean mNeedsSizeUpdate; + Boolean mFirstSetFormat; + Boolean mAlignDataWithFillerChunks; + +public: + + AudioFileObject (UInt32 inFileType) + : mNumBytes(0), + mNumPackets(0), + mDataOffset(0), + mIsOptimized(1), + mFileType(inFileType), + mFileRef(NULL), + mFileD(-1), + mPermissions(0), + mIsInitialized (false), + mDataSource(0), + mMaximumPacketSize(0), + mPacketTable(NULL), + mDeferSizeUpdates(1), + mNeedsSizeUpdate(false), + mFirstSetFormat(true), + mAlignDataWithFillerChunks(true) + { + memset(&mDataFormat, 0, sizeof(mDataFormat)); + } + + virtual ~AudioFileObject(); + + +/* Public API Function Implementation */ + // The DoSomething() versions of these functions are wrappers that perform a standard prologue. + // The Something() methods are those which should be overridden in the subclasses. + + OSStatus DoCreate( CFURLRef inFileRef, + const AudioStreamBasicDescription *inFormat, + UInt32 inFlags); + + virtual OSStatus Create( CFURLRef inFileRef, + const AudioStreamBasicDescription *inFormat); + + OSStatus DoOpen( CFURLRef inFileRef, + SInt8 inPermissions, + int inFD); + + virtual OSStatus Open( CFURLRef inFileRef, + SInt8 inPermissions, + int inFD); + + OSStatus DoOpenWithCallbacks( + void * inRefCon, + AudioFile_ReadProc inReadFunc, + AudioFile_WriteProc inWriteFunc, + AudioFile_GetSizeProc inGetSizeFunc, + AudioFile_SetSizeProc inSetSizeFunc); + + + OSStatus DoInitialize( CFURLRef inFileRef, + const AudioStreamBasicDescription *inFormat, + UInt32 inFlags); + + virtual OSStatus Initialize( CFURLRef inFileRef, + const AudioStreamBasicDescription *inFormat, + UInt32 inFlags); + + OSStatus DoInitializeWithCallbacks( + void * inRefCon, + AudioFile_ReadProc inReadFunc, + AudioFile_WriteProc inWriteFunc, + AudioFile_GetSizeProc inGetSizeFunc, + AudioFile_SetSizeProc inSetSizeFunc, + UInt32 inFileType, + const AudioStreamBasicDescription *inFormat, + UInt32 inFlags); + + virtual OSStatus OpenFromDataSource(void); + + virtual OSStatus InitializeDataSource(const AudioStreamBasicDescription *inFormat, UInt32 inFlags); + + OSStatus DoClose(); + + virtual OSStatus Close(); + + OSStatus DoOptimize(); + + virtual OSStatus Optimize(); + + virtual OSStatus ReadBytes( Boolean inUseCache, + SInt64 inStartingByte, + UInt32 *ioNumBytes, + void *outBuffer); + + virtual OSStatus WriteBytes( Boolean inUseCache, + SInt64 inStartingByte, + UInt32 *ioNumBytes, + const void *inBuffer); + + virtual OSStatus ReadPackets( Boolean inUseCache, + UInt32 *outNumBytes, + AudioStreamPacketDescription *outPacketDescriptions, + SInt64 inStartingPacket, + UInt32 *ioNumPackets, + void *outBuffer); + + virtual OSStatus ReadPacketData( + Boolean inUseCache, + UInt32 *ioNumBytes, + AudioStreamPacketDescription *outPacketDescriptions, + SInt64 inStartingPacket, + UInt32 *ioNumPackets, + void *outBuffer); + + virtual OSStatus ReadPacketDataVBR( + Boolean inUseCache, + UInt32 *ioNumBytes, + AudioStreamPacketDescription *outPacketDescriptions, + SInt64 inStartingPacket, + UInt32 *ioNumPackets, + void *outBuffer); + + virtual OSStatus HowManyPacketsCanBeReadIntoBuffer(UInt32* ioNumBytes, SInt64 inStartingPacket, UInt32 *ioNumPackets); + + virtual OSStatus ReadPacketDataVBR_InTable( + Boolean inUseCache, + UInt32 *ioNumBytes, + AudioStreamPacketDescription *outPacketDescriptions, + SInt64 inStartingPacket, + UInt32 *ioNumPackets, + void *outBuffer); + + virtual OSStatus WritePackets( Boolean inUseCache, + UInt32 inNumBytes, + const AudioStreamPacketDescription *inPacketDescriptions, + SInt64 inStartingPacket, + UInt32 *ioNumPackets, + const void *inBuffer); +/* Property Support */ + + virtual OSStatus GetPropertyInfo ( + AudioFilePropertyID inPropertyID, + UInt32 *outDataSize, + UInt32 *isWritable); + + virtual OSStatus GetProperty ( AudioFilePropertyID inPropertyID, + UInt32 *ioDataSize, + void *ioPropertyData); + + virtual OSStatus SetProperty ( AudioFilePropertyID inPropertyID, + UInt32 inDataSize, + const void *inPropertyData); + + UInt32 GetFileType() const { return mFileType; } + void SetFileType(UInt32 inFileType) { mFileType = inFileType; } + + // this will set the format in memory only. + virtual OSStatus SetDataFormat(const AudioStreamBasicDescription* inStreamFormat); + + // this will update the format info on disk and in memory. + virtual OSStatus UpdateDataFormat(const AudioStreamBasicDescription* inStreamFormat); + + const UInt32 GetBytesPerPacket() const { return mDataFormat.mBytesPerPacket; } + + const AudioStreamBasicDescription &GetDataFormat() const { return mDataFormat; } + + virtual OSStatus GetFormatListInfo( UInt32 &outDataSize, + UInt32 &outWritable); + + virtual OSStatus GetFormatList( UInt32 &ioDataSize, + AudioFormatListItem *ioPropertyData); + + virtual OSStatus SetFormatList( UInt32 inDataSize, + const AudioFormatListItem *inPropertyData); + + virtual OSStatus UpdateSize() { return noErr; } + UInt32 DeferSizeUpdates() { return mDeferSizeUpdates; } + void SetDeferSizeUpdates(UInt32 inFlag) { mDeferSizeUpdates = inFlag; } + OSStatus UpdateSizeIfNeeded(); + OSStatus SizeChanged(); + + Boolean IsOptimized() const { return mIsOptimized != 0; } + void SetIsOptimized(Boolean inIsOptimized) { mIsOptimized = inIsOptimized ? 1 : 0; } + + Boolean AlignDataWithFillerChunks() const { return mAlignDataWithFillerChunks; } + + virtual SInt64 GetNumBytes() { return mNumBytes; } + virtual void SetNumBytes(SInt64 inNumBytes) { mNumBytes = inNumBytes; } + + // this will update the header size info on disk + OSStatus UpdateNumBytes(SInt64 inNumBytes); + + virtual SInt64 GetNumPackets(){ return mNumPackets; } + virtual void SetNumPackets(SInt64 inNumPackets) { mNumPackets = inNumPackets; } + + // this will update the header size info on disk + OSStatus UpdateNumPackets(SInt64 inNumPackets); + + virtual OSStatus PacketToFrame(SInt64 inPacket, SInt64& outFirstFrameInPacket); + virtual OSStatus FrameToPacket(SInt64 inFrame, SInt64& outPacket, UInt32& outFrameOffsetInPacket); + + virtual OSStatus PacketToByte(AudioBytePacketTranslation* abpt); + + virtual OSStatus ByteToPacket(AudioBytePacketTranslation* abpt); + + virtual OSStatus GetBitRate( UInt32 *outBitRate); + + virtual OSStatus GetMagicCookieDataSize( UInt32 *outDataSize, + UInt32 *isWritable); + + virtual OSStatus GetMagicCookieData( UInt32 *ioDataSize, + void *ioPropertyData); + + virtual OSStatus SetMagicCookieData( UInt32 inDataSize, + const void *inPropertyData); + + virtual OSStatus GetMarkerListSize( UInt32 *outDataSize, + UInt32 *isWritable); + + virtual OSStatus GetMarkerList( UInt32 *ioDataSize, + AudioFileMarkerList *ioMarkerList); + + virtual OSStatus SetMarkerList( UInt32 inDataSize, + const AudioFileMarkerList *inMarkerList); + + + virtual OSStatus GetRegionListSize( UInt32 *outDataSize, + UInt32 *isWritable); + + virtual OSStatus GetRegionList( UInt32 *ioDataSize, + AudioFileRegionList *ioRegionList); + + virtual OSStatus SetRegionList( UInt32 inDataSize, + const AudioFileRegionList *inRegionList); + + virtual OSStatus GetChannelLayoutSize( UInt32 *outDataSize, + UInt32 *isWritable); + + virtual OSStatus GetChannelLayout( UInt32 *ioDataSize, + AudioChannelLayout *ioChannelLayout); + + virtual OSStatus SetChannelLayout( UInt32 inDataSize, + const AudioChannelLayout *inChannelLayout); + + + virtual OSStatus GetInfoDictionarySize( UInt32 *outDataSize, + UInt32 *isWritable); + + virtual OSStatus GetInfoDictionary( CACFDictionary *infoDict); + + virtual OSStatus SetInfoDictionary( CACFDictionary *infoDict); + + virtual OSStatus GetSoundCheckDictionarySize( UInt32 *outDataSize, + UInt32 *isWritable) { return kAudioFileUnsupportedPropertyError; } + + virtual OSStatus GetSoundCheckDictionary( CACFDictionary *infoDict) { return kAudioFileUnsupportedPropertyError; } + + virtual OSStatus SetSoundCheckDictionary( CACFDictionary *infoDict) { return kAudioFileUnsupportedPropertyError; } + + virtual OSStatus GetLoudnessInfo( CACFDictionary *infoDict) { return kAudioFileUnsupportedPropertyError; } + + virtual OSStatus GetSoundCheckDictionaryFromLoudnessInfo(CACFDictionary* outInfoDict) { return kAudioFileUnsupportedPropertyError; } + virtual OSStatus GetLoudnessInfoFromSoundCheckDictionary(CACFDictionary* outInfoDict) { return kAudioFileUnsupportedPropertyError; } + + virtual OSStatus SetLoudnessInfo( CACFDictionary *infoDict) { return kAudioFileUnsupportedPropertyError; } + + virtual OSStatus GetLoudnessInfoSize( UInt32 *outDataSize, + UInt32 *isWritable) { return kAudioFileUnsupportedPropertyError; } + + virtual OSStatus GenerateLoudnessInfo( CACFDictionary *infoDict) { return kAudioFileUnsupportedPropertyError; } + + virtual OSStatus GetEstimatedDuration( Float64* duration); + + virtual OSStatus CountUserData( UInt32 inUserDataID, + UInt32 *outNumberItems); + + virtual OSStatus GetUserDataSize( UInt32 inUserDataID, + UInt32 inIndex, + UInt32 *outDataSize); + + virtual OSStatus GetUserData( UInt32 inUserDataID, + UInt32 inIndex, + UInt32 *ioDataSize, + void *ioUserData); + + virtual OSStatus SetUserData( UInt32 inUserDataID, + UInt32 inIndex, + UInt32 inDataSize, + const void *inUserData); + + virtual OSStatus RemoveUserData( UInt32 inUserDataID, + UInt32 inIndex); + + virtual OSStatus GetLyrics(CFStringRef *outLyrics) { return kAudioFileUnsupportedPropertyError; } + + + Boolean CanRead() const { return mPermissions & kAudioFileReadPermission; } + Boolean CanWrite() const { return mPermissions & kAudioFileWritePermission; } + + void SetPermissions(SInt8 inPermissions) { mPermissions = inPermissions; } + +/* Other Helper Methods: (some may not be necessary depending on how things are refactored) */ + + OSStatus OpenFile(SInt8 inPermissions, int inFD); + + OSStatus CreateDataFile (CFURLRef inFileRef, int &outFileD); + + OSStatus AddDurationToInfoDictionary(CACFDictionary *infoDict, Float64 &inDuration); + + virtual Boolean IsDataFormatSupported(const AudioStreamBasicDescription *inFormat) = 0; + virtual Boolean IsDataFormatValid(const AudioStreamBasicDescription *inFormat); + + virtual OSStatus IsValidFilePosition(SInt64 /*position*/) { return noErr; } + + OSStatus MoveData(SInt64 fromPos, SInt64 toPos, SInt64 size); + +/* Accessors: */ + Boolean IsInitialized() const { return mIsInitialized; } + void SetInitialized(Boolean inFlag) { mIsInitialized = inFlag; } + + DataSource* GetDataSource() const { return mDataSource; } + void SetDataSource(DataSource *inDataSource); + + void SetURL (CFURLRef inURL); + + virtual UInt32 GetMaximumPacketSize() { return mMaximumPacketSize; } + virtual UInt32 FindMaximumPacketSize() { return mMaximumPacketSize; } + virtual void SetMaximumPacketSize(const UInt32 inPacketSize) { mMaximumPacketSize = inPacketSize; } + + virtual UInt32 GetPacketSizeUpperBound() { return GetMaximumPacketSize (); } + + SInt64 GetDataOffset() const { return mDataOffset; } + void SetDataOffset(SInt64 inOffset) { mDataOffset = inOffset; } + + // I like this idiom better than DoesPacketTableExist+NewPacketTable: + CompressedPacketTable* GetPacketTable(Boolean inCreateIt = false) + { + if (!mPacketTable && inCreateIt) + mPacketTable = new CompressedPacketTable(mDataFormat.mFramesPerPacket); + return mPacketTable; + } + void ClearPacketTable() + { + DeletePacketTable(); + GetPacketTable(true); + } + + virtual OSStatus ScanForPackets(SInt64 inToPacketCount, DataSource* inDataSrc = NULL, bool fullyParsedIfEndOfDataReached = true) + { + // In formats that read packets lazily, this will be overridden to scan for packets up to the index. + if (inToPacketCount > GetNumPackets()) + return kAudioFileEndOfFileError; + + return noErr; + } + + void AppendPacket(const AudioStreamPacketDescription &inPacket) + { + CompressedPacketTable* packetTable = GetPacketTable(true); + UInt32 numFramesInPacket = mDataFormat.mFramesPerPacket ? mDataFormat.mFramesPerPacket : inPacket.mVariableFramesInPacket; + + AudioStreamPacketDescriptionExtended pext; + memset(&pext, 0, sizeof(pext)); + pext.mStartOffset = inPacket.mStartOffset; + pext.mDataByteSize = inPacket.mDataByteSize; + pext.mVariableFramesInPacket = inPacket.mVariableFramesInPacket; + pext.mFrameOffset = numFramesInPacket + (packetTable->size() ? packetTable->back().mFrameOffset : 0); + + packetTable->push_back(pext); + if (inPacket.mDataByteSize > mMaximumPacketSize) + mMaximumPacketSize = inPacket.mDataByteSize; + } + void DeletePacketTable() { delete mPacketTable; mPacketTable = NULL;} + SInt64 GetPacketTableSize() { return mPacketTable ? mPacketTable->size() : 0; } + OSStatus GetPacketDescriptions(UInt32 inStartingPacket, UInt32 *ioDataSize, AudioStreamPacketDescription *outPacketDescriptions) + { + if (outPacketDescriptions == NULL) return kAudioFileUnspecifiedError; + if (mPacketTable) + { + // only get as many packet descriptions as can fit in outPacketDescriptions + UInt32 count = *ioDataSize / sizeof(AudioStreamPacketDescription); + if (count + inStartingPacket > GetPacketTableSize()) + count = (UInt32)(GetPacketTableSize() - inStartingPacket); + + *ioDataSize = 0; + for (UInt32 i = inStartingPacket; i < (count + inStartingPacket); i++) + { + AudioStreamPacketDescription curPacket = (*mPacketTable)[i]; + outPacketDescriptions[i].mStartOffset = curPacket.mStartOffset - GetDataOffset(); + outPacketDescriptions[i].mVariableFramesInPacket = curPacket.mVariableFramesInPacket; + outPacketDescriptions[i].mDataByteSize = curPacket.mDataByteSize; + *ioDataSize += sizeof(AudioStreamPacketDescription); + } + } + else + *ioDataSize = 0; + + return noErr; + } + +#if DEBUG + void DumpPacketTable() + { + if (mPacketTable) { + SInt64 size = mPacketTable->size(); + printf("PacketTable size %d\n", (int)size); + for (SInt64 i = 0; i < size; i++) { + AudioStreamPacketDescription curPacket = (*mPacketTable)[i]; + printf("dpkt %5qd %8qd %5d %5d\n", i, curPacket.mStartOffset, (int)curPacket.mDataByteSize, (int)curPacket.mVariableFramesInPacket); + } + } + } +#endif + + Boolean GetNeedsSizeUpdate() const { return mNeedsSizeUpdate; } + void SetNeedsSizeUpdate(Boolean inNeedsSizeUpdate) { mNeedsSizeUpdate = inNeedsSizeUpdate; } + + CFURLRef GetURL () const { return mFileRef; } + + virtual OSStatus GetSourceBitDepth(SInt32& outValue) { outValue = 0; return kAudioFileUnsupportedPropertyError; } + virtual OSStatus SetSourceBitDepth(SInt32 inValue) { return kAudioFileUnsupportedPropertyError; } + + virtual OSStatus GetAlbumArtwork(CFDataRef& outValue) { outValue = NULL; return kAudioFileUnsupportedPropertyError; } + virtual OSStatus SetAlbumArtwork(CFDataRef inValue){ return kAudioFileUnsupportedPropertyError; } + +private: + + void SetAlignDataWithFillerChunks(Boolean inFlag) { mAlignDataWithFillerChunks = inFlag; } + + OSStatus ValidateFormatAndData(); + +/* debug */ +// virtual void PrintFile (FILE* inFile, const char *indent) = 0; +}; + +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +inline Boolean cfstrcmpi(CFStringRef a, CFStringRef b) +{ + // case insensitive CFString compare + return CFStringCompare(a, b, kCFCompareCaseInsensitive) == kCFCompareEqualTo; +} + +CFBundleRef GetAudioToolboxBundle(); + + +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +#endif diff --git a/libs/appleutility/CoreAudio/AudioFile/AFPublic/CompressedPacketTable.cpp b/libs/appleutility/CoreAudio/AudioFile/AFPublic/CompressedPacketTable.cpp new file mode 100644 index 0000000000..ba07580bba --- /dev/null +++ b/libs/appleutility/CoreAudio/AudioFile/AFPublic/CompressedPacketTable.cpp @@ -0,0 +1,216 @@ +/* + File: CompressedPacketTable.cpp + Abstract: CompressedPacketTable.h + Version: 1.1 + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple + 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 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. + + Copyright (C) 2014 Apple Inc. All Rights Reserved. + +*/ +#include "CompressedPacketTable.h" +#include "CAAutoDisposer.h" + +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +const UInt32 CompressedPacketTable::kShift = 5; +const UInt32 CompressedPacketTable::kMask = 31; + +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +CompressedPacketTable::~CompressedPacketTable() +{ + size_t size = mBases.size(); + for (size_t i = 0; i < size; ++i) { + free(mBases[i].mDescs); + } +} + +void CompressedPacketTable::push_back(const AudioStreamPacketDescriptionExtended& inDesc) +{ + SInt64 baseIndex = mSize >> kShift; + UInt32 packetIndex = (UInt32)(mSize & kMask); + + if (packetIndex == 0) { + // first packet in a new sequence. create a new PacketBase. + PacketBase newBase; + newBase.mBaseOffset = 0; + newBase.mDescs = CA_malloc((kMask+1) * sizeof(AudioStreamPacketDescriptionExtended)); + newBase.mDescType = kExtendedPacketDescription; + mBases.push_back(newBase); + } + + PacketBase& base = mBases[(size_t)baseIndex]; + AudioStreamPacketDescriptionExtended* descs = (AudioStreamPacketDescriptionExtended*)base.mDescs; + descs[packetIndex] = inDesc; + + if (packetIndex == kMask) { + // last packet in a sequence. compress the sequence. + Compress(base); + } + + mSize++; +} + +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +#define ACCESS_TYPE(TYPE) \ + case k##TYPE##ContiguousPacketDescription : { \ + TYPE##ContiguousPacketDescription* descs = (TYPE##ContiguousPacketDescription*)base.mDescs; \ + packetOffset = packetIndex ? descs[packetIndex-1].mNextOffset : 0; \ + packetSize = (UInt32)(descs[packetIndex].mNextOffset - packetOffset); \ + } break; \ + case k##TYPE##DiscontiguousPacketDescription : { \ + TYPE##DiscontiguousPacketDescription* descs = (TYPE##DiscontiguousPacketDescription*)base.mDescs; \ + packetOffset = packetIndex ? descs[packetIndex-1].mNextOffset : 0; \ + packetSize = descs[packetIndex].mDataByteSize; \ + } break; + +const AudioStreamPacketDescriptionExtended CompressedPacketTable::operator[](SInt64 inPacketIndex) const +{ + SInt64 baseIndex = inPacketIndex >> kShift; + UInt32 packetIndex = (UInt32)(inPacketIndex & kMask); + + if ((size_t)baseIndex >= mBases.size()) + throw -1; + + const PacketBase& base = mBases[(size_t)baseIndex]; + + SInt64 packetOffset = 0; + UInt32 packetSize = 0; + + switch (base.mDescType) + { + ACCESS_TYPE(Tiny) + ACCESS_TYPE(Small) + ACCESS_TYPE(Big) + case kExtendedPacketDescription : + return ((AudioStreamPacketDescriptionExtended*)base.mDescs)[packetIndex]; + } + + AudioStreamPacketDescriptionExtended outDesc; + outDesc.mStartOffset = base.mBaseOffset + packetOffset; + outDesc.mDataByteSize = packetSize; + outDesc.mVariableFramesInPacket = 0; + outDesc.mFrameOffset = mFramesPerPacket * inPacketIndex; + + //printf("get %d %10qd %10qd %2d %10qd %6d %10qd\n", base.mDescType, inPacketIndex, baseIndex, packetIndex, outDesc.mStartOffset, outDesc.mDataByteSize, outDesc.mFrameOffset); + + return outDesc; +} + +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +bool CompressedPacketTable::isContiguous(PacketBase& base) +{ + AudioStreamPacketDescriptionExtended* descs = (AudioStreamPacketDescriptionExtended*)base.mDescs; + SInt64 expectedOffset = descs[0].mStartOffset + descs[0].mDataByteSize; + for (UInt32 i = 1; i <= kMask; ++i) { + if (expectedOffset != descs[i].mStartOffset) return false; + expectedOffset += descs[i].mDataByteSize; + } + return true; +} + +bool CompressedPacketTable::hasVariableFrames(PacketBase& base) +{ + AudioStreamPacketDescriptionExtended* descs = (AudioStreamPacketDescriptionExtended*)base.mDescs; + for (UInt32 i = 0; i <= kMask; ++i) { + if (descs[i].mVariableFramesInPacket) return true; + } + return false; +} + +UInt32 CompressedPacketTable::largestPacket(PacketBase& base) +{ + UInt32 maxPacketSize = 0; + AudioStreamPacketDescriptionExtended* descs = (AudioStreamPacketDescriptionExtended*)base.mDescs; + for (UInt32 i = 0; i <= kMask; ++i) { + UInt32 packetSize = descs[i].mDataByteSize; + if (packetSize > maxPacketSize) maxPacketSize = packetSize; + } + return maxPacketSize; +} + +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +#define COMPRESS_TYPE(TYPE, BITS) \ + if (contiguous) { \ + TYPE##ContiguousPacketDescription* newDescs = (TYPE##ContiguousPacketDescription*)CA_malloc((kMask+1) * sizeof(TYPE##ContiguousPacketDescription)); \ + base.mDescs = newDescs; \ + base.mDescType = k##TYPE##ContiguousPacketDescription; \ + for (UInt32 i = 0; i <= kMask; ++i) { \ + newDescs[i].mNextOffset = (BITS)(descs[i].mStartOffset + descs[i].mDataByteSize - baseOffset); \ + } \ + free(descs); \ + } else { \ + TYPE##DiscontiguousPacketDescription* newDescs = (TYPE##DiscontiguousPacketDescription*)CA_malloc((kMask+1) * sizeof(TYPE##DiscontiguousPacketDescription)); \ + base.mDescs = newDescs; \ + base.mDescType = k##TYPE##DiscontiguousPacketDescription; \ + for (UInt32 i = 0; i <= kMask; ++i) { \ + newDescs[i].mNextOffset = i == kMask ? 0 : (BITS)(descs[i+1].mStartOffset - baseOffset); \ + newDescs[i].mDataByteSize = descs[i].mDataByteSize; \ + } \ + free(descs); \ + } \ + return; + +void CompressedPacketTable::Compress(PacketBase& base) +{ + if (hasVariableFrames(base)) + return; + + bool contiguous = isContiguous(base); + + AudioStreamPacketDescriptionExtended* descs = (AudioStreamPacketDescriptionExtended*)base.mDescs; + SInt64 delta = descs[kMask].mStartOffset + descs[kMask].mDataByteSize - descs[0].mStartOffset; + + SInt64 baseOffset = descs[0].mStartOffset; + base.mBaseOffset = baseOffset; + + if (delta <= 65535LL) { + COMPRESS_TYPE(Tiny, UInt16) + } else if (delta <= 4294967295LL && largestPacket(base) <= 65535) { + COMPRESS_TYPE(Small, UInt32) + } else { + COMPRESS_TYPE(Big, SInt64) + } +} + +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/libs/appleutility/CoreAudio/AudioFile/AFPublic/CompressedPacketTable.h b/libs/appleutility/CoreAudio/AudioFile/AFPublic/CompressedPacketTable.h new file mode 100644 index 0000000000..47e28ca499 --- /dev/null +++ b/libs/appleutility/CoreAudio/AudioFile/AFPublic/CompressedPacketTable.h @@ -0,0 +1,186 @@ +/* + File: CompressedPacketTable.h + Abstract: Part of CoreAudio Utility Classes + Version: 1.1 + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple + 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 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. + + Copyright (C) 2014 Apple Inc. All Rights Reserved. + +*/ +#include <iterator> +#include <vector> +#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__) + #include <CoreAudio/CoreAudioTypes.h> +#else + #include "CoreAudioTypes.h" +#endif + +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +struct AudioStreamPacketDescriptionExtended : AudioStreamPacketDescription +{ + SInt64 mFrameOffset; // this is the sum of the mVariableFramesInPacket up to this point so we can binary search. +}; +typedef struct AudioStreamPacketDescriptionExtended AudioStreamPacketDescriptionExtended; + +inline bool operator < (const AudioStreamPacketDescriptionExtended& a, const AudioStreamPacketDescriptionExtended& b) +{ + return a.mFrameOffset < b.mFrameOffset; +} + +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +class CompressedPacketTable +{ +public: + CompressedPacketTable(UInt32 inFramesPerPacket) : mSize(0), mFramesPerPacket(inFramesPerPacket) {} + ~CompressedPacketTable(); + + SInt64 size() const { return mSize; } + void push_back(const AudioStreamPacketDescriptionExtended& inDesc); + + const AudioStreamPacketDescriptionExtended operator[](SInt64 inPacketIndex) const; + const AudioStreamPacketDescriptionExtended front() const { return (*this)[0]; } + const AudioStreamPacketDescriptionExtended back() const { return (*this)[mSize-1]; } + + //SInt64 PacketForByte(SInt64 inByteOffset) const; + SInt64 ByteForPacket(SInt64 inPacketIndex) const { return (*this)[inPacketIndex].mStartOffset; } + + class iterator { + public: + typedef std::input_iterator_tag iterator_category; + typedef iterator pointer; + typedef SInt64 difference_type; + typedef AudioStreamPacketDescriptionExtended value_type; + typedef value_type& reference; + + iterator() : mTable(NULL), mIndex(0) {} + iterator(const CompressedPacketTable* table, SInt64 index) : mTable(table), mIndex(index) {} + iterator(const iterator& that) : mTable(that.mTable), mIndex(that.mIndex) {} + + iterator& operator=(const iterator& that) { mTable = that.mTable; mIndex = that.mIndex; return *this; } + + const AudioStreamPacketDescriptionExtended operator*() const { return (*mTable)[mIndex]; } + const AudioStreamPacketDescriptionExtended* const operator->() { mValue = (*mTable)[mIndex]; return &mValue; } + iterator& operator++() { ++mIndex; return *this; } + iterator& operator--() { --mIndex; return *this; } + + SInt64 operator-(const iterator& that) { return mIndex - that.mIndex; } + const iterator operator-(SInt64 index) { return iterator(mTable, mIndex - index); } + const iterator operator+(SInt64 index) { return iterator(mTable, mIndex + index); } + bool operator==(const iterator& that) { return mIndex == that.mIndex; } + bool operator!=(const iterator& that) { return mIndex != that.mIndex; } + bool operator>(const iterator& that) { return mIndex > that.mIndex; } + bool operator<(const iterator& that) { return mIndex < that.mIndex; } + private: + const CompressedPacketTable* mTable; + SInt64 mIndex; + AudioStreamPacketDescriptionExtended mValue; // in order to support operator-> . + }; + + iterator begin() const { return iterator(this, 0); } + iterator end() const { return iterator(this, mSize); } + +private: + struct TinyContiguousPacketDescription + { + UInt16 mNextOffset; + }; + + struct TinyDiscontiguousPacketDescription : TinyContiguousPacketDescription + { + UInt16 mDataByteSize; + }; + + // There could be a 24 bit packet description. But ALAC is who usually needs SmallContiguousPacketDescription and + // it already uses 8x fewer packet descriptions than AAC due to the mFramesPerPacket being 8x greater. + // So there isn't as great a need for saving space. 4 bytes per packet is OK for ALAC. + + struct SmallContiguousPacketDescription + { + UInt32 mNextOffset; + }; + + struct SmallDiscontiguousPacketDescription : SmallContiguousPacketDescription + { + UInt16 mDataByteSize; + }; + + struct BigContiguousPacketDescription + { + UInt64 mNextOffset; + }; + + struct BigDiscontiguousPacketDescription : BigContiguousPacketDescription + { + UInt32 mDataByteSize; + }; + + struct PacketBase + { + SInt64 mBaseOffset; + UInt8 mDescType; + void* mDescs; + }; + + enum { + kTinyContiguousPacketDescription, + kTinyDiscontiguousPacketDescription, + kSmallContiguousPacketDescription, + kSmallDiscontiguousPacketDescription, + kBigContiguousPacketDescription, + kBigDiscontiguousPacketDescription, + kExtendedPacketDescription + }; + static const UInt32 kShift; + static const UInt32 kMask; + + bool isContiguous(PacketBase& base); + bool hasVariableFrames(PacketBase& base); + UInt32 largestPacket(PacketBase& base); + + void Compress(PacketBase& base); + +private: + std::vector<PacketBase> mBases; + UInt64 mSize; + UInt32 mFramesPerPacket; +}; + diff --git a/libs/appleutility/CoreAudio/AudioFile/AFPublic/DataSource.cpp b/libs/appleutility/CoreAudio/AudioFile/AFPublic/DataSource.cpp new file mode 100644 index 0000000000..c8a93d2756 --- /dev/null +++ b/libs/appleutility/CoreAudio/AudioFile/AFPublic/DataSource.cpp @@ -0,0 +1,689 @@ +/* + File: DataSource.cpp + Abstract: DataSource.h + Version: 1.1 + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple + 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 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. + + Copyright (C) 2014 Apple Inc. All Rights Reserved. + +*/ +#include "DataSource.h" +#if TARGET_OS_WIN32 + #include <io.h> +#else + #include <unistd.h> + #include <fcntl.h> +#endif +#include <sys/stat.h> +#include <algorithm> + +#define VERBOSE 0 + +////////////////////////////////////////////////////////////////////////////////////////// + + +const UInt16 kPositionModeMask = 3; + +DataSource::DataSource(Boolean inCloseOnDelete) + : mCloseOnDelete(inCloseOnDelete) +{ +} + +DataSource::~DataSource() +{ +} + +SInt64 DataSource::CalcOffset( UInt16 positionMode, + SInt64 positionOffset, + SInt64 currentOffset, + SInt64 size) +{ + SInt64 newOffset = 0; + switch (positionMode & kPositionModeMask) { + //case fsAtMark : newOffset = currentOffset; break; + case SEEK_SET : newOffset = positionOffset; break; + case SEEK_END : newOffset = size + positionOffset; break; + case SEEK_CUR : newOffset = positionOffset + currentOffset; break; + } + return newOffset; +} + +////////////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////////////// + +#if 0 + +MacFile_DataSource::MacFile_DataSource( FSIORefNum inForkRefNum, SInt8 inPermissions, Boolean inCloseOnDelete) + : DataSource(inCloseOnDelete), mFileNum(inForkRefNum), mPermissions(inPermissions) +{ +} + +MacFile_DataSource::~MacFile_DataSource() +{ + if (mCloseOnDelete) FSCloseFork(mFileNum); +} + + +OSStatus MacFile_DataSource::GetSize(SInt64& outSize) +{ + outSize = -1; // in case of error + OSStatus err = FSGetForkSize(mFileNum, &outSize); + return err; +} + +OSStatus MacFile_DataSource::GetPos(SInt64& outPos) const +{ + return FSGetForkPosition(mFileNum, &outPos); +} + +OSStatus MacFile_DataSource::SetSize(SInt64 inSize) +{ + return FSSetForkSize(mFileNum, SEEK_SET, inSize); +} + + +OSStatus MacFile_DataSource::ReadBytes( + UInt16 positionMode, + SInt64 positionOffset, + UInt32 requestCount, + void *buffer, + UInt32* actualCount) +{ + if (actualCount) *actualCount = 0; + if (!buffer) return kAudio_ParamError; + ByteCount bc_actualCount = 0; + OSStatus err = FSReadFork(mFileNum, positionMode, positionOffset, requestCount, buffer, &bc_actualCount); + if (actualCount) *actualCount = (UInt32)bc_actualCount; + return err; +} + +OSStatus MacFile_DataSource::WriteBytes( + UInt16 positionMode, + SInt64 positionOffset, + UInt32 requestCount, + const void *buffer, + UInt32* actualCount) +{ + if (!buffer) return kAudio_ParamError; + ByteCount bc_actualCount = 0; + OSStatus err = FSWriteFork(mFileNum, positionMode, positionOffset, requestCount, buffer, &bc_actualCount); + if (actualCount) *actualCount = (UInt32)bc_actualCount; + return err; +} +#endif + +////////////////////////////////////////////////////////////////////////////////////////// + +#define kAudioFileNoCacheMask 0x20 + +UnixFile_DataSource::UnixFile_DataSource( int inFD, SInt8 inPermissions, Boolean inCloseOnDelete) + : DataSource(inCloseOnDelete), mFileD(inFD), mPermissions(inPermissions), mNoCache(0), mCachedSize(-1), mFilePointer(0) +{ +} + +UnixFile_DataSource::~UnixFile_DataSource() +{ + if (mCloseOnDelete) close(mFileD); +} + +OSStatus UnixFile_DataSource::GetSize(SInt64& outSize) +{ +#if 0 // 6764274 using the cached file size causes a regression for apps that play a file while writing to it. + if (mCachedSize >= 0) { + outSize = mCachedSize; + return noErr; + } +#endif + outSize = -1; // in case of error + struct stat stbuf; + if (fstat (mFileD, &stbuf) == -1) return kAudio_FileNotFoundError; + outSize = mCachedSize = stbuf.st_size; + return noErr; +} + +OSStatus UnixFile_DataSource::SetSize(SInt64 inSize) +{ + mCachedSize = -1; +#if TARGET_OS_WIN32 + if (chsize (mFileD, inSize)) return kAudioFilePermissionsError; +#else + if (ftruncate (mFileD, inSize) == -1) return kAudioFilePermissionsError; +#endif + mCachedSize = inSize; + return noErr; +} + + +OSStatus UnixFile_DataSource::GetPos(SInt64& outPos) const +{ + outPos = mFilePointer; + return noErr; +} + +SInt64 UnixFile_DataSource::UFCurrentOffset (UInt16 positionMode, + SInt64 positionOffset) +{ + SInt64 offset = -1; + switch (positionMode & kPositionModeMask) + { + /*case fsAtMark : + { + SInt64 pos; + OSStatus result = GetPos (pos); + if (result) return result; + offset = pos; + break; + }*/ + case SEEK_SET : + { + offset = positionOffset; + break; + } + case SEEK_END : + { + SInt64 size; + OSStatus result = GetSize (size); + if (result) return result; + offset = size + positionOffset; + break; + } + case SEEK_CUR : + { + SInt64 pos; + OSStatus result = GetPos (pos); + if (result) return result; + offset = positionOffset + pos; + break; + } + } + return offset; +} + +OSStatus UnixFile_DataSource::ReadBytes( UInt16 positionMode, + SInt64 positionOffset, + UInt32 requestCount, + void *buffer, + UInt32* actualCount) +{ + if (actualCount) *actualCount = 0; + if (!buffer) return kAudio_ParamError; + + // can't use current offset as we need to go to the disk too much + SInt64 offset = UFCurrentOffset (positionMode, positionOffset); + if (offset < 0) return kAudioFilePositionError; + +#if 0 // 6571050 fstat-ing the file every read causes a performance regression + // 5931571 check that read may exceed eof and curtail it. + do { + SInt64 size; + OSStatus serr = GetSize(size); + if (serr) break; + SInt64 remain = size - offset; + if (remain < 0) requestCount = 0; + else if (requestCount > remain) requestCount = remain; + } while (false); +#endif + + if (requestCount <= 0) { + if (actualCount) *actualCount = 0; + return noErr; + } + +#if !TARGET_OS_WIN32 + UInt32 noCache = positionMode & kAudioFileNoCacheMask ? 1 : 0; + if (noCache != mNoCache) { + mNoCache = noCache; + fcntl(mFileD, F_NOCACHE, mNoCache); + } +#endif + + size_t readBytes = requestCount; +#if TARGET_OS_WIN32 + lseek(mFileD, offset, SEEK_SET); + int numBytes = read (mFileD, buffer, readBytes); +#else + ssize_t numBytes = pread (mFileD, buffer, readBytes, offset); +#endif + if (numBytes == -1) return kAudioFilePositionError; + mFilePointer = offset + numBytes; + + if (actualCount) *actualCount = (UInt32)numBytes; + return noErr; +} + +OSStatus UnixFile_DataSource::WriteBytes(UInt16 positionMode, + SInt64 positionOffset, + UInt32 requestCount, + const void *buffer, + UInt32* actualCount) +{ + if (!buffer) return kAudio_ParamError; + + // can't use current offset as we need to go to the disk too much + SInt64 offset = UFCurrentOffset (positionMode, positionOffset); + if (offset < 0) return kAudioFilePositionError; + + mCachedSize = -1; + + size_t writeBytes = requestCount; + +#if !TARGET_OS_WIN32 + UInt32 noCache = positionMode & kAudioFileNoCacheMask ? 1 : 0; + if (noCache != mNoCache) { + mNoCache = noCache; + fcntl(mFileD, F_NOCACHE, mNoCache); + } +#endif + +#if TARGET_OS_WIN32 + lseek(mFileD, offset, SEEK_SET); + int numBytes = write (mFileD, buffer, writeBytes); +#else + ssize_t numBytes = pwrite (mFileD, buffer, writeBytes, offset); +#endif + if (numBytes == -1) return kAudioFilePositionError; + mFilePointer = offset + numBytes; + + if (actualCount) *actualCount = (UInt32)numBytes; + return noErr; +} + +////////////////////////////////////////////////////////////////////////////////////////// + +#define NO_CACHE 0 + +OSStatus Cached_DataSource::ReadFromHeaderCache( + SInt64 offset, + UInt32 requestCount, + void *buffer, + UInt32* actualCount) +{ + if (actualCount) *actualCount = 0; + OSStatus err = noErr; + ByteCount theActualCount = 0; + +#if VERBOSE + printf("read from header %lld %lu %lld %lu\n", offset, requestCount, 0LL, mHeaderCacheSize); +#endif + + if (!mHeaderCache()) + { + mHeaderCache.allocBytes(mHeaderCacheSize, true); + err = mDataSource->ReadBytes(SEEK_SET, 0, mHeaderCacheSize, mHeaderCache(), &mHeaderCacheSize); + if (err == kAudioFileEndOfFileError) err = noErr; + if (err) return err; + } + + ByteCount firstPart = std::min((ByteCount)requestCount, (ByteCount)(mHeaderCacheSize - offset)); + ByteCount secondPart = requestCount - firstPart; + + memcpy(buffer, mHeaderCache + (ByteCount)offset, firstPart); + theActualCount = firstPart; + + if (secondPart) { + UInt32 secondPartActualCount = 0; + err = mDataSource->ReadBytes(SEEK_SET, mHeaderCacheSize, static_cast<UInt32>(secondPart), (char*)buffer + firstPart, &secondPartActualCount); + theActualCount += secondPartActualCount; + } + + if (actualCount) *actualCount = (UInt32)theActualCount; + mOffset = offset + theActualCount; + + return err; +} + +OSStatus Cached_DataSource::ReadBytes( + UInt16 positionMode, + SInt64 positionOffset, + UInt32 requestCount, + void *buffer, + UInt32* actualCount) +{ + if (actualCount) *actualCount = 0; + OSStatus err = noErr; + SInt64 size; + UInt32 theActualCount = 0; + + if (!buffer) return kAudio_ParamError; + + if ((positionMode & kPositionModeMask) != SEEK_END) size = 0; // not used in this case + else + { + err = GetSize(size); + if (err) return err; + } + + SInt64 offset = CalcOffset(positionMode, positionOffset, mOffset, size); + if (offset < 0) return kAudioFilePositionError; + + if (offset < mHeaderCacheSize) { + return ReadFromHeaderCache(offset, requestCount, buffer, actualCount); + } + +#if NO_CACHE + err = mDataSource->ReadBytes(positionMode, positionOffset, requestCount, buffer, &theActualCount); + mOffset = offset + theActualCount; +#else + + SInt64 cacheEnd = mBodyCacheOffset + mBodyCacheCurSize; + if (mBodyCache() && requestCount < mBodyCacheSize && offset >= mBodyCacheOffset && offset < cacheEnd) + { + if (offset + requestCount <= cacheEnd) + { + // request is entirely within cache +#if VERBOSE + printf("request is entirely within cache %lld %lu %lld %lu\n", offset, requestCount, mBodyCacheOffset, mBodyCacheCurSize); +#endif + memcpy(buffer, mBodyCache + (size_t)(offset - mBodyCacheOffset), requestCount); + theActualCount = requestCount; + } + else + { + // part of request is within cache. copy, read next cache block, copy. +#if VERBOSE + printf("part of request is within cache %lld %lu %lld %lu\n", offset, requestCount, mBodyCacheOffset, mBodyCacheCurSize); +#endif + + // copy first part. + ByteCount firstPart = (ByteCount)(cacheEnd - offset); + ByteCount secondPart = requestCount - firstPart; +#if VERBOSE + printf("memcpy offset %lld mBodyCacheOffset %lld offset - mBodyCacheOffset %lld firstPart %lu requestCount %lu\n", + offset, mBodyCacheOffset, offset - mBodyCacheOffset, firstPart, requestCount); +#endif + memcpy(buffer, mBodyCache + (size_t)(offset - mBodyCacheOffset), firstPart); + + theActualCount = static_cast<UInt32>(firstPart); + + // read new block + SInt64 nextOffset = mBodyCacheOffset + mBodyCacheCurSize; + err = mDataSource->ReadBytes(SEEK_SET, nextOffset, mBodyCacheSize, mBodyCache(), &mBodyCacheCurSize); + + if (err == kAudioFileEndOfFileError) err = noErr; + if (err) goto leave; + + mBodyCacheOffset = nextOffset; + + // copy second part + secondPart = std::min(secondPart, (ByteCount)mBodyCacheCurSize); + if (secondPart) memcpy((char*)buffer + firstPart, mBodyCache(), secondPart); + theActualCount = static_cast<UInt32>(firstPart + secondPart); + } + } + else + { + if (requestCount > mBodyCacheSize) + { +#if VERBOSE + printf("large request %lld %lu %lld %lu\n", offset, requestCount, mBodyCacheOffset, mBodyCacheCurSize); +#endif + // the request is larger than we normally cache, just do a read and don't cache. + err = mDataSource->ReadBytes(positionMode, positionOffset, requestCount, buffer, &theActualCount); + mOffset = offset + theActualCount; + } + else + { + // request is outside cache. read new block. +#if VERBOSE + printf("request is outside cache %lld %lu %lld %lu\n", offset, requestCount, mBodyCacheOffset, mBodyCacheCurSize); +#endif + if (!mBodyCache()) + { + mBodyCache.allocBytes(mBodyCacheSize, true); +#if VERBOSE + printf("alloc mBodyCache %08X\n", mBodyCache()); +#endif + } + mBodyCacheOffset = offset; + err = mDataSource->ReadBytes(SEEK_SET, mBodyCacheOffset, mBodyCacheSize, mBodyCache(), &mBodyCacheCurSize); +#if VERBOSE + printf("read %08X %d mBodyCacheOffset %lld %lu %lu\n", err, err, mBodyCacheOffset, mBodyCacheSize, mBodyCacheCurSize); +#endif + if (err == kAudioFileEndOfFileError) err = noErr; + if (err) return err; + + theActualCount = std::min(requestCount, mBodyCacheCurSize); + memcpy(buffer, mBodyCache(), theActualCount); + } + + } + +leave: +#endif + if (actualCount) *actualCount = (UInt32)theActualCount; +#if VERBOSE + printf("<<read err %d actualCount %lu\n", err, *actualCount); +#endif + return err; +} + +OSStatus Cached_DataSource::WriteBytes( + UInt16 positionMode, + SInt64 positionOffset, + UInt32 requestCount, + const void *buffer, + UInt32* actualCount) +{ + OSStatus err = noErr; + SInt64 size; + + if (!buffer) return kAudio_ParamError; + + if ((positionMode & kPositionModeMask) != SEEK_END) size = 0; // not used in this case + else + { + err = GetSize(size); + if (err) return err; + } + + SInt64 offset = CalcOffset(positionMode, positionOffset, mOffset, size); + if (offset < 0) return kAudioFilePositionError; + + if (mHeaderCache() && offset < mHeaderCacheSize) + { + // header cache write through + ByteCount firstPart = std::min((ByteCount)requestCount, (ByteCount)(mHeaderCacheSize - offset)); +#if VERBOSE + printf("header cache write through %lu %lu\n", mHeaderCacheSize, firstPart); +#endif + memcpy(mHeaderCache + (size_t)offset, buffer, firstPart); + } + +#if VERBOSE + printf("write %lld %lu %lld %d %lld\n", offset, requestCount, mOffset, positionMode, positionOffset); +#endif + + SInt64 cacheEnd = mBodyCacheOffset + mBodyCacheCurSize; + if (mBodyCache() && offset >= mBodyCacheOffset && offset < cacheEnd) + { + // body cache write through + ByteCount firstPart = std::min((SInt64)requestCount, cacheEnd - offset); +#if VERBOSE + printf("body cache write through %lld %lu %lld %lu\n", mBodyCacheOffset, mBodyCacheCurSize, offset, firstPart); +#endif + memcpy(mBodyCache + (offset - mBodyCacheOffset), buffer, firstPart); + } + + UInt32 theActualCount; + err = mDataSource->WriteBytes(positionMode, positionOffset, requestCount, buffer, &theActualCount); + + mOffset = offset + theActualCount; + if (actualCount) *actualCount = (UInt32)theActualCount; + + return err; +} + + +////////////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////////////// + +Seekable_DataSource::Seekable_DataSource( void * inClientData, + AudioFile_ReadProc inReadFunc, + AudioFile_WriteProc inWriteFunc, + AudioFile_GetSizeProc inGetSizeFunc, + AudioFile_SetSizeProc inSetSizeFunc) + : DataSource(false), mClientData(inClientData), mReadFunc(inReadFunc), mWriteFunc(inWriteFunc), + mSizeFunc(inGetSizeFunc), mSetSizeFunc(inSetSizeFunc) +{ +} + +Seekable_DataSource::~Seekable_DataSource() +{ +} + + +OSStatus Seekable_DataSource::GetSize(SInt64& outSize) +{ + if (!mSizeFunc) { + outSize = LLONG_MAX; + } else { + outSize = (*mSizeFunc)(mClientData); + } + return noErr; +} + +OSStatus Seekable_DataSource::SetSize(SInt64 inSize) +{ + if (!mSetSizeFunc) return kAudioFileOperationNotSupportedError; + return (*mSetSizeFunc)(mClientData, inSize); +} + +OSStatus Seekable_DataSource::ReadBytes( + UInt16 positionMode, + SInt64 positionOffset, + UInt32 requestCount, + void *buffer, + UInt32* actualCount) +{ + OSStatus err; + + if (actualCount) *actualCount = 0; + if (!mReadFunc) return kAudioFileOperationNotSupportedError; + if (!buffer) return kAudio_ParamError; + + positionMode &= kPositionModeMask; + + SInt64 size; + err = GetSize(size); + if (err) return err; + + SInt64 offset = CalcOffset(positionMode, positionOffset, mOffset, size); + + // request is outside bounds of file + if (offset < 0) + return kAudioFilePositionError; + if (offset >= size) + return kAudioFileEndOfFileError; + + // reduce request if it exceeds the amount available + requestCount = static_cast<UInt32>(std::min((SInt64)requestCount, size - offset)); + + UInt32 theActualCount = 0; + err = (*mReadFunc)(mClientData, offset, requestCount, buffer, &theActualCount); + if (actualCount) *actualCount = theActualCount; + mOffset = offset + theActualCount; + return err; +} + + +OSStatus Seekable_DataSource::WriteBytes( + UInt16 positionMode, + SInt64 positionOffset, + UInt32 requestCount, + const void *buffer, + UInt32* actualCount) +{ + OSStatus err; + + if (!mWriteFunc) return kAudioFileOperationNotSupportedError; + if (!buffer) return kAudio_ParamError; + + SInt64 size; + positionMode &= kPositionModeMask; + if (positionMode != SEEK_END) size = 0; // not used in this case + else + { + err = GetSize(size); + if (err) return err; + } + + SInt64 offset = CalcOffset(positionMode, positionOffset, mOffset, size); + if (offset < 0) return kAudioFilePositionError; + + UInt32 theActualCount; + err = (*mWriteFunc)(mClientData, offset, requestCount, buffer, &theActualCount); + if (err) return err; + if (actualCount) *actualCount = theActualCount; + mOffset = offset + theActualCount; + return noErr; +} + +////////////////////////////////////////////////////////////////////////////////////////// + +OSStatus Buffer_DataSource::ReadBytes( + UInt16 positionMode, + SInt64 positionOffset, + UInt32 requestCount, + void *buffer, + UInt32* actualCount) +{ + if (actualCount) *actualCount = 0; + SInt64 offsetWithinBuffer = CalcOffset(positionMode, positionOffset, mOffset, mDataByteSize + mStartOffset) - mStartOffset; + if (offsetWithinBuffer < 0 || offsetWithinBuffer >= mDataByteSize) return kAudioFilePositionError; + + SInt64 bytesAfterOffset = mDataByteSize - offsetWithinBuffer; + SInt64 theActualCount = std::min(bytesAfterOffset, (SInt64)requestCount); + + if (theActualCount <= 0) { + if (actualCount) *actualCount = 0; + return kAudio_ParamError; + } + + memcpy(buffer, mData + offsetWithinBuffer, theActualCount); + + if (actualCount) *actualCount = static_cast<UInt32>(theActualCount); + mOffset = offsetWithinBuffer + theActualCount; + + return noErr; +} + + + +////////////////////////////////////////////////////////////////////////////////////////// diff --git a/libs/appleutility/CoreAudio/AudioFile/AFPublic/DataSource.h b/libs/appleutility/CoreAudio/AudioFile/AFPublic/DataSource.h new file mode 100644 index 0000000000..6c79c94df9 --- /dev/null +++ b/libs/appleutility/CoreAudio/AudioFile/AFPublic/DataSource.h @@ -0,0 +1,372 @@ +/* + File: DataSource.h + Abstract: Part of CoreAudio Utility Classes + Version: 1.1 + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple + 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 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. + + Copyright (C) 2014 Apple Inc. All Rights Reserved. + +*/ +#ifndef __DataSource_h__ +#define __DataSource_h__ + +#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__) + #include <AudioToolbox/AudioFile.h> +#else + #include <ConditionalMacros.h> + #include "AudioFile.h" +#endif +#include <stdlib.h> +#include <stdio.h> +#include <stdexcept> +#include "CAAutoDisposer.h" + +////////////////////////////////////////////////////////////////////////////////////////// + +class DataSource +{ +public: + + DataSource(Boolean inCloseOnDelete); + virtual ~DataSource(); + + virtual OSStatus GetSize32(UInt32& outSize) + { + SInt64 size64; + OSStatus err = GetSize(size64); + if (err) return err; + if (size64 > 0x00000000FFFFffffLL) return kAudioFileDoesNotAllow64BitDataSizeError; + outSize = (UInt32)size64; + return noErr; + } + + virtual OSStatus GetSize(SInt64& outSize) =0; + + virtual OSStatus SetSize(SInt64 inSize)=0; + + virtual OSStatus GetPos(SInt64& outPos) const=0; + + /* non seekable data sources should use fsAtMark for the positionMode (or SEEK_CUR with offset zero, + or SEEK_SET with offset equal to the current position in the stream, in other words no seeking from the + current position is allowed.) + */ + + virtual OSStatus ReadBytes( UInt16 positionMode, + SInt64 positionOffset, + UInt32 requestCount, + void *buffer, + UInt32* actualCount)=0; + + virtual OSStatus WriteBytes(UInt16 positionMode, + SInt64 positionOffset, + UInt32 requestCount, + const void *buffer, + UInt32* actualCount)=0; + + virtual void SetCloseOnDelete(Boolean inFlag) { mCloseOnDelete = inFlag; } + + virtual Boolean CanSeek() const=0; + virtual Boolean CanGetSize() const=0; + virtual Boolean CanSetSize() const=0; + virtual Boolean CanRead() const=0; + virtual Boolean CanWrite() const=0; + +protected: + Boolean mCloseOnDelete; + + /* utility method */ + SInt64 CalcOffset( UInt16 positionMode, + SInt64 positionOffset, + SInt64 currentOffset, + SInt64 size); +}; + +////////////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////////////// + +/* + Initialize with a Macintosh file fork ref num as obtained from FSOpenFork. +*/ + +#if 0 + +class MacFile_DataSource : public DataSource +{ + FSIORefNum mFileNum; + SInt8 mPermissions; + +public: + + MacFile_DataSource( FSIORefNum inForkRefNum, SInt8 inPermissions, Boolean inCloseOnDelete); + virtual ~MacFile_DataSource(); + + virtual OSStatus GetSize(SInt64& outSize); + virtual OSStatus GetPos(SInt64& outPos) const; + + virtual OSStatus SetSize(SInt64 inSize); + + virtual OSStatus ReadBytes( UInt16 positionMode, + SInt64 positionOffset, + UInt32 requestCount, + void *buffer, + UInt32* actualCount); + + virtual OSStatus WriteBytes(UInt16 positionMode, + SInt64 positionOffset, + UInt32 requestCount, + const void *buffer, + UInt32* actualCount); + + virtual Boolean CanSeek() const { return true; } + virtual Boolean CanGetSize() const { return true; } + virtual Boolean CanSetSize() const { return true; } + + virtual Boolean CanRead() const { return mPermissions & kAudioFileReadPermission; } + virtual Boolean CanWrite() const { return mPermissions & kAudioFileWritePermission; } +}; +#endif + + +class UnixFile_DataSource : public DataSource +{ + int mFileD; + SInt8 mPermissions; + UInt32 mNoCache; + SInt64 mCachedSize; + SInt64 mFilePointer; + +public: + + UnixFile_DataSource( int inFD, SInt8 inPermissions, Boolean inCloseOnDelete); + virtual ~UnixFile_DataSource(); + + virtual OSStatus GetSize(SInt64& outSize); + virtual OSStatus GetPos(SInt64& outPos) const; + + virtual OSStatus SetSize(SInt64 inSize); + + virtual OSStatus ReadBytes( UInt16 positionMode, + SInt64 positionOffset, + UInt32 requestCount, + void *buffer, + UInt32* actualCount); + + virtual OSStatus WriteBytes(UInt16 positionMode, + SInt64 positionOffset, + UInt32 requestCount, + const void *buffer, + UInt32* actualCount); + + virtual Boolean CanSeek() const { return true; } + virtual Boolean CanGetSize() const { return true; } + virtual Boolean CanSetSize() const { return true; } + + virtual Boolean CanRead() const { return mPermissions & kAudioFileReadPermission; } + virtual Boolean CanWrite() const { return mPermissions & kAudioFileWritePermission; } + +private: + + SInt64 UFCurrentOffset (UInt16 positionMode, + SInt64 positionOffset); +}; + +////////////////////////////////////////////////////////////////////////////////////////// + +////////////////////////////////////////////////////////////////////////////////////////// + +/* + A wrapper that caches the wrapped source's header. +*/ +class Cached_DataSource : public DataSource +{ + DataSource* mDataSource; + CAAutoFree<UInt8> mHeaderCache; + UInt32 mHeaderCacheSize; + CAAutoFree<UInt8> mBodyCache; + UInt32 mBodyCacheSize; + UInt32 mBodyCacheCurSize; + SInt64 mBodyCacheOffset; + SInt64 mOffset; + Boolean mOwnDataSource; + +public: + + Cached_DataSource(DataSource* inDataSource, UInt32 inHeaderCacheSize = 4096, UInt32 inBodyCacheSize = 32768, Boolean inOwnDataSource = true) + : DataSource(false), + mDataSource(inDataSource), mHeaderCacheSize(inHeaderCacheSize), + mBodyCacheSize(inBodyCacheSize), mBodyCacheCurSize(0), mBodyCacheOffset(-1), + mOffset(0), + mOwnDataSource(inOwnDataSource) + { + } + + virtual ~Cached_DataSource() + { + if (mOwnDataSource) delete mDataSource; + } + + + virtual OSStatus GetSize(SInt64& outSize) { return mDataSource->GetSize(outSize); } + virtual OSStatus GetPos(SInt64& outPos) const { return mDataSource->GetPos(outPos); } + + virtual OSStatus SetSize(SInt64 inSize) { return mDataSource->SetSize(inSize); } + + virtual OSStatus ReadBytes( UInt16 positionMode, + SInt64 positionOffset, + UInt32 requestCount, + void *buffer, + UInt32* actualCount); + + virtual OSStatus WriteBytes( UInt16 positionMode, + SInt64 positionOffset, + UInt32 requestCount, + const void *buffer, + UInt32* actualCount); + + OSStatus ReadFromHeaderCache( SInt64 offset, + UInt32 requestCount, + void *buffer, + UInt32* actualCount); + + virtual Boolean CanSeek() const { return mDataSource->CanSeek(); } + virtual Boolean CanGetSize() const { return mDataSource->CanGetSize(); } + virtual Boolean CanSetSize() const { return mDataSource->CanSetSize(); } + + virtual Boolean CanRead() const { return mDataSource->CanRead(); } + virtual Boolean CanWrite() const { return mDataSource->CanWrite(); } +}; + +////////////////////////////////////////////////////////////////////////////////////////// + +////////////////////////////////////////////////////////////////////////////////////////// + +////////////////////////////////////////////////////////////////////////////////////////// + + +/* This class calls user supplied routines on demand. */ + +class Seekable_DataSource : public DataSource +{ + void * mClientData; + SInt64 mOffset; + + AudioFile_ReadProc mReadFunc; + AudioFile_WriteProc mWriteFunc; + AudioFile_GetSizeProc mSizeFunc; + AudioFile_SetSizeProc mSetSizeFunc; + +public: + Seekable_DataSource( void * inClientData, + AudioFile_ReadProc inReadFunc, + AudioFile_WriteProc inWriteFunc, + AudioFile_GetSizeProc inGetSizeFunc, + AudioFile_SetSizeProc inSetSizeFunc + ); + + virtual ~Seekable_DataSource(); + + virtual OSStatus GetSize(SInt64& outSize); + virtual OSStatus GetPos(SInt64& outPos) const { outPos = mOffset; return noErr; }; + + virtual OSStatus SetSize(SInt64 inSize); + + virtual OSStatus ReadBytes( UInt16 positionMode, + SInt64 positionOffset, + UInt32 requestCount, + void *buffer, + UInt32* actualCount); + + virtual OSStatus WriteBytes(UInt16 positionMode, + SInt64 positionOffset, + UInt32 requestCount, + const void *buffer, + UInt32* actualCount); + + virtual Boolean CanSeek() const { return true; } + virtual Boolean CanGetSize() const { return mSizeFunc != 0; } + virtual Boolean CanSetSize() const { return mSetSizeFunc != 0; } + virtual Boolean CanRead() const { return mReadFunc != 0; } + virtual Boolean CanWrite() const { return mWriteFunc != 0; } +}; + +////////////////////////////////////////////////////////////////////////////////////////// + +class Buffer_DataSource : public DataSource +{ + UInt32 mDataByteSize; + const char * mData; + + SInt64 mStartOffset; + SInt64 mOffset; +public: + Buffer_DataSource( UInt32 inDataByteSize, + const void * inData, + SInt64 inStartOffset = 0 + ) : DataSource(false), mDataByteSize(inDataByteSize), mData((const char*)inData), mStartOffset(inStartOffset), mOffset(mStartOffset) {} + + virtual ~Buffer_DataSource() {} + + virtual OSStatus GetSize(SInt64& outSize) { outSize = mDataByteSize + mStartOffset; return noErr; } + virtual OSStatus GetPos(SInt64& outPos) const { outPos = mOffset; return noErr; }; + + virtual OSStatus SetSize(SInt64 inSize) { throw std::runtime_error("not writable"); } + + virtual OSStatus ReadBytes( UInt16 positionMode, + SInt64 positionOffset, + UInt32 requestCount, + void *buffer, + UInt32* actualCount); + + virtual OSStatus WriteBytes(UInt16 positionMode, + SInt64 positionOffset, + UInt32 requestCount, + const void *buffer, + UInt32* actualCount) { throw std::runtime_error("not writable"); } + + virtual Boolean CanSeek() const { return true; } + virtual Boolean CanGetSize() const { return true; } + virtual Boolean CanSetSize() const { return false; } + virtual Boolean CanRead() const { return true; } + virtual Boolean CanWrite() const { return false; } +}; + +////////////////////////////////////////////////////////////////////////////////////////// + +#endif |