this repo has no description
at fixPythonPipStalling 439 lines 18 kB view raw
1/* Copyright: � Copyright 2005 Apple Computer, Inc. All rights reserved. 2 3 Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc. 4 ("Apple") in consideration of your agreement to the following terms, and your 5 use, installation, modification or redistribution of this Apple software 6 constitutes acceptance of these terms. If you do not agree with these terms, 7 please do not use, install, modify or redistribute this Apple software. 8 9 In consideration of your agreement to abide by the following terms, and subject 10 to these terms, Apple grants you a personal, non-exclusive license, under Apple�s 11 copyrights in this original Apple software (the "Apple Software"), to use, 12 reproduce, modify and redistribute the Apple Software, with or without 13 modifications, in source and/or binary forms; provided that if you redistribute 14 the Apple Software in its entirety and without modifications, you must retain 15 this notice and the following text and disclaimers in all such redistributions of 16 the Apple Software. Neither the name, trademarks, service marks or logos of 17 Apple Computer, Inc. may be used to endorse or promote products derived from the 18 Apple Software without specific prior written permission from Apple. Except as 19 expressly stated in this notice, no other rights or licenses, express or implied, 20 are granted by Apple herein, including but not limited to any patent rights that 21 may be infringed by your derivative works or by other works in which the Apple 22 Software may be incorporated. 23 24 The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO 25 WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED 26 WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR 27 PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN 28 COMBINATION WITH YOUR PRODUCTS. 29 30 IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR 31 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 32 GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 33 ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION 34 OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT 35 (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN 36 ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 37*/ 38/*============================================================================= 39 CAAudioFile.h 40 41=============================================================================*/ 42 43#ifndef __CAAudioFile_h__ 44#define __CAAudioFile_h__ 45 46#include <AvailabilityMacros.h> 47 48#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__) 49 #include <AudioToolbox/AudioToolbox.h> 50#else 51 #include <AudioToolbox.h> 52#endif 53 54#include "CAStreamBasicDescription.h" 55#include "CABufferList.h" 56#include "CAAudioChannelLayout.h" 57#include "CAXException.h" 58#include "CAMath.h" 59 60#ifndef CAAF_USE_EXTAUDIOFILE 61// option: use AudioToolbox/ExtAudioFile.h? Only available on Tiger. 62 #if MAC_OS_X_VERSION_MIN_REQUIRED <= MAC_OS_X_VERSION_10_3 63 // we are building software that must be deployable on Panther or earlier 64 #define CAAF_USE_EXTAUDIOFILE 0 65 #else 66 // else we require Tiger and can use the API 67 #define CAAF_USE_EXTAUDIOFILE 1 68 #endif 69#endif 70 71#ifndef MAC_OS_X_VERSION_10_4 72 // we have pre-Tiger headers; add our own declarations 73 typedef UInt32 AudioFileTypeID; 74 enum { 75 kExtAudioFileError_InvalidProperty = -66561, 76 kExtAudioFileError_InvalidPropertySize = -66562, 77 kExtAudioFileError_NonPCMClientFormat = -66563, 78 kExtAudioFileError_InvalidChannelMap = -66564, // number of channels doesn't match format 79 kExtAudioFileError_InvalidOperationOrder = -66565, 80 kExtAudioFileError_InvalidDataFormat = -66566, 81 kExtAudioFileError_MaxPacketSizeUnknown = -66567, 82 kExtAudioFileError_InvalidSeek = -66568, // writing, or offset out of bounds 83 kExtAudioFileError_AsyncWriteTooLarge = -66569, 84 kExtAudioFileError_AsyncWriteBufferOverflow = -66570 // an async write could not be completed in time 85 }; 86#else 87 #if !defined(__COREAUDIO_USE_FLAT_INCLUDES__) 88 #include <AudioToolbox/ExtendedAudioFile.h> 89 #else 90 #include "ExtendedAudioFile.h" 91 #endif 92#endif 93 94// _______________________________________________________________________________________ 95// Wrapper class for an AudioFile, supporting encode/decode to/from a PCM client format 96class CAAudioFile { 97public: 98 // implementation-independent helpers 99 void Open(const char *filePath) { 100 FSRef fsref; 101 XThrowIfError(FSPathMakeRef((UInt8 *)filePath, &fsref, NULL), "locate audio file"); 102 Open(fsref); 103 } 104 105 bool HasConverter() const { return GetConverter() != NULL; } 106 107 double GetDurationSeconds() { 108 double sr = GetFileDataFormat().mSampleRate; 109 return fnonzero(sr) ? GetNumberFrames() / sr : 0.; 110 } 111 // will be 0 if the file's frames/packet is 0 (variable) 112 // or the file's sample rate is 0 (unknown) 113 114#if CAAF_USE_EXTAUDIOFILE 115public: 116 CAAudioFile() : mExtAF(NULL) { } 117 virtual ~CAAudioFile() { if (mExtAF) Close(); } 118 119 void Open(const FSRef &fsref) { 120 // open an existing file 121 XThrowIfError(ExtAudioFileOpen(&fsref, &mExtAF), "ExtAudioFileOpen failed"); 122 } 123 124 void CreateNew(const FSRef &inParentDir, CFStringRef inFileName, AudioFileTypeID inFileType, const AudioStreamBasicDescription &inStreamDesc, const AudioChannelLayout *inChannelLayout=NULL) { 125 XThrowIfError(ExtAudioFileCreateNew(&inParentDir, inFileName, inFileType, &inStreamDesc, inChannelLayout, &mExtAF), "ExtAudioFileCreateNew failed"); 126 } 127 128 void Wrap(AudioFileID fileID, bool forWriting) { 129 // use this to wrap an AudioFileID opened externally 130 XThrowIfError(ExtAudioFileWrapAudioFileID(fileID, forWriting, &mExtAF), "ExtAudioFileWrapAudioFileID failed"); 131 } 132 133 void Close() { 134 XThrowIfError(ExtAudioFileDispose(mExtAF), "ExtAudioFileClose failed"); 135 mExtAF = NULL; 136 } 137 138 const CAStreamBasicDescription &GetFileDataFormat() { 139 UInt32 size = sizeof(mFileDataFormat); 140 XThrowIfError(ExtAudioFileGetProperty(mExtAF, kExtAudioFileProperty_FileDataFormat, &size, &mFileDataFormat), "Couldn't get file's data format"); 141 return mFileDataFormat; 142 } 143 144 const CAAudioChannelLayout & GetFileChannelLayout() { 145 return FetchChannelLayout(mFileChannelLayout, kExtAudioFileProperty_FileChannelLayout); 146 } 147 148 void SetFileChannelLayout(const CAAudioChannelLayout &layout) { 149 XThrowIfError(ExtAudioFileSetProperty(mExtAF, kExtAudioFileProperty_FileChannelLayout, layout.Size(), &layout.Layout()), "Couldn't set file's channel layout"); 150 mFileChannelLayout = layout; 151 } 152 153 const CAStreamBasicDescription &GetClientDataFormat() { 154 UInt32 size = sizeof(mClientDataFormat); 155 XThrowIfError(ExtAudioFileGetProperty(mExtAF, kExtAudioFileProperty_ClientDataFormat, &size, &mClientDataFormat), "Couldn't get client data format"); 156 return mClientDataFormat; 157 } 158 159 const CAAudioChannelLayout & GetClientChannelLayout() { 160 return FetchChannelLayout(mClientChannelLayout, kExtAudioFileProperty_ClientChannelLayout); 161 } 162 163 void SetClientFormat(const CAStreamBasicDescription &dataFormat, const CAAudioChannelLayout *layout=NULL) { 164 XThrowIfError(ExtAudioFileSetProperty(mExtAF, kExtAudioFileProperty_ClientDataFormat, sizeof(dataFormat), &dataFormat), "Couldn't set client format"); 165 if (layout) 166 SetClientChannelLayout(*layout); 167 } 168 169 void SetClientChannelLayout(const CAAudioChannelLayout &layout) { 170 XThrowIfError(ExtAudioFileSetProperty(mExtAF, kExtAudioFileProperty_ClientChannelLayout, layout.Size(), &layout.Layout()), "Couldn't set client channel layout"); 171 } 172 173 AudioConverterRef GetConverter() const { 174 UInt32 size = sizeof(AudioConverterRef); 175 AudioConverterRef converter; 176 XThrowIfError(ExtAudioFileGetProperty(mExtAF, kExtAudioFileProperty_AudioConverter, &size, &converter), "Couldn't get file's AudioConverter"); 177 return converter; 178 } 179 180 OSStatus SetConverterProperty(AudioConverterPropertyID inPropertyID, UInt32 inPropertyDataSize, const void *inPropertyData, bool inCanFail=false) 181 { 182 OSStatus err = AudioConverterSetProperty(GetConverter(), inPropertyID, inPropertyDataSize, inPropertyData); 183 if (!inCanFail) 184 XThrowIfError(err, "Couldn't set audio converter property"); 185 if (!err) { 186 // must tell the file that we have changed the converter; a NULL converter config is sufficient 187 CFPropertyListRef config = NULL; 188 XThrowIfError(ExtAudioFileSetProperty(mExtAF, kExtAudioFileProperty_ConverterConfig, sizeof(CFPropertyListRef), &config), "couldn't signal the file that the converter has changed"); 189 } 190 return err; 191 } 192 193 SInt64 GetNumberFrames() { 194 SInt64 length; 195 UInt32 size = sizeof(SInt64); 196 XThrowIfError(ExtAudioFileGetProperty(mExtAF, kExtAudioFileProperty_FileLengthFrames, &size, &length), "Couldn't get file's length"); 197 return length; 198 } 199 200 void SetNumberFrames(SInt64 length) { 201 XThrowIfError(ExtAudioFileSetProperty(mExtAF, kExtAudioFileProperty_FileLengthFrames, sizeof(SInt64), &length), "Couldn't set file's length"); 202 } 203 204 void Seek(SInt64 pos) { 205 XThrowIfError(ExtAudioFileSeek(mExtAF, pos), "Couldn't seek in audio file"); 206 } 207 208 SInt64 Tell() { 209 SInt64 pos; 210 XThrowIfError(ExtAudioFileTell(mExtAF, &pos), "Couldn't get file's mark"); 211 return pos; 212 } 213 214 void Read(UInt32 &ioFrames, AudioBufferList *ioData) { 215 XThrowIfError(ExtAudioFileRead(mExtAF, &ioFrames, ioData), "Couldn't read audio file"); 216 } 217 218 void Write(UInt32 inFrames, const AudioBufferList *inData) { 219 XThrowIfError(ExtAudioFileWrite(mExtAF, inFrames, inData), "Couldn't write audio file"); 220 } 221 222 void SetIOBufferSizeBytes(UInt32 bufferSizeBytes) { 223 XThrowIfError(ExtAudioFileSetProperty(mExtAF, kExtAudioFileProperty_IOBufferSizeBytes, sizeof(UInt32), &bufferSizeBytes), "Couldn't set audio file's I/O buffer size"); 224 } 225 226private: 227 const CAAudioChannelLayout & FetchChannelLayout(CAAudioChannelLayout &layoutObj, ExtAudioFilePropertyID propID) { 228 UInt32 size; 229 XThrowIfError(ExtAudioFileGetPropertyInfo(mExtAF, propID, &size, NULL), "Couldn't get info about channel layout"); 230 AudioChannelLayout *layout = (AudioChannelLayout *)malloc(size); 231 OSStatus err = ExtAudioFileGetProperty(mExtAF, propID, &size, layout); 232 if (err) { 233 free(layout); 234 XThrowIfError(err, "Couldn't get channel layout"); 235 } 236 layoutObj = layout; 237 free(layout); 238 return layoutObj; 239 } 240 241 242private: 243 ExtAudioFileRef mExtAF; 244 245 CAStreamBasicDescription mFileDataFormat; 246 CAAudioChannelLayout mFileChannelLayout; 247 248 CAStreamBasicDescription mClientDataFormat; 249 CAAudioChannelLayout mClientChannelLayout; 250#endif 251 252#if !CAAF_USE_EXTAUDIOFILE 253 CAAudioFile(); 254 virtual ~CAAudioFile(); 255 256 // --- second-stage initializers --- 257 // Use exactly one of the following: 258 // - Open 259 // - PrepareNew followed by Create 260 // - Wrap 261 262 void Open(const FSRef &fsref); 263 // open an existing file 264 265 void CreateNew(const FSRef &inParentDir, CFStringRef inFileName, AudioFileTypeID inFileType, const AudioStreamBasicDescription &inStreamDesc, const AudioChannelLayout *inChannelLayout=NULL); 266 267 void Wrap(AudioFileID fileID, bool forWriting); 268 // use this to wrap an AudioFileID opened externally 269 270 // --- 271 272 void Close(); 273 // In case you want to close the file before the destructor executes 274 275 // --- Data formats --- 276 277 // Allow specifying the file's channel layout. Must be called before SetClientFormat. 278 // When writing, the specified channel layout is written to the file (if the file format supports 279 // the channel layout). When reading, the specified layout overrides the one read from the file, 280 // if any. 281 void SetFileChannelLayout(const CAAudioChannelLayout &layout); 282 283 // This specifies the data format which the client will use for reading/writing the file, 284 // which may be different from the file's format. An AudioConverter is created if necessary. 285 // The client format must be linear PCM. 286 void SetClientFormat(const CAStreamBasicDescription &dataFormat, const CAAudioChannelLayout *layout=NULL); 287 void SetClientDataFormat(const CAStreamBasicDescription &dataFormat) { SetClientFormat(dataFormat, NULL); } 288 void SetClientChannelLayout(const CAAudioChannelLayout &layout) { SetClientFormat(mClientDataFormat, &layout); } 289 290 // Wrapping the underlying converter, if there is one 291 OSStatus SetConverterProperty(AudioConverterPropertyID inPropertyID, 292 UInt32 inPropertyDataSize, 293 const void * inPropertyData, 294 bool inCanFail = false); 295 void SetConverterConfig(CFArrayRef config) { 296 SetConverterProperty(kAudioConverterPropertySettings, sizeof(config), &config); } 297 CFArrayRef GetConverterConfig(); 298 299 // --- I/O --- 300 // All I/O is sequential, but you can seek to an arbitrary position when reading. 301 // SeekToPacket and TellPacket's packet numbers are in the file's data format, not the client's. 302 // However, ReadPackets/WritePackets use packet counts in the client data format. 303 304 void Read(UInt32 &ioNumFrames, AudioBufferList *ioData); 305 void Write(UInt32 numFrames, const AudioBufferList *data); 306 307 // These can fail for files without a constant mFramesPerPacket 308 void Seek(SInt64 frameNumber); 309 SInt64 Tell() const; // frameNumber 310 311 // --- Accessors --- 312 // note: client parameters only valid if SetClientFormat has been called 313 AudioFileID GetAudioFileID() const { return mAudioFile; } 314 const CAStreamBasicDescription &GetFileDataFormat() const { return mFileDataFormat; } 315 const CAStreamBasicDescription &GetClientDataFormat() const { return mClientDataFormat; } 316 const CAAudioChannelLayout & GetFileChannelLayout() const { return mFileChannelLayout; } 317 const CAAudioChannelLayout & GetClientChannelLayout() const { return mClientChannelLayout; } 318 AudioConverterRef GetConverter() const { return mConverter; } 319 320 UInt32 GetFileMaxPacketSize() const { return mFileMaxPacketSize; } 321 UInt32 GetClientMaxPacketSize() const { return mClientMaxPacketSize; } 322 SInt64 GetNumberPackets() const { 323 SInt64 npackets; 324 UInt32 propertySize = sizeof(npackets); 325 XThrowIfError(AudioFileGetProperty(mAudioFile, kAudioFilePropertyAudioDataPacketCount, &propertySize, &npackets), "get audio file's packet count"); 326 return npackets; 327 } 328 SInt64 GetNumberFrames() const; 329 // will be 0 if the file's frames/packet is 0 (variable) 330 void SetNumberFrames(SInt64 length); // should only be set on a PCM file 331 332 // --- Tunable performance parameters --- 333 void SetUseCache(bool b) { mUseCache = b; } 334 void SetIOBufferSizeBytes(UInt32 bufferSizeBytes) { mIOBufferSizeBytes = bufferSizeBytes; } 335 UInt32 GetIOBufferSizeBytes() { return mIOBufferSizeBytes; } 336 void * GetIOBuffer() { return mIOBufferList.mBuffers[0].mData; } 337 void SetIOBuffer(void *buf); 338 339 // -- Profiling --- 340#if CAAUDIOFILE_PROFILE 341 void EnableProfiling(bool b) { mProfiling = b; } 342 UInt64 TicksInConverter() const { return (mTicksInConverter > 0) ? (mTicksInConverter - mTicksInReadInConverter) : 0; } 343 UInt64 TicksInIO() const { return mTicksInIO; } 344#endif 345 346// _______________________________________________________________________________________ 347private: 348 SInt64 FileDataOffset(); 349 void SeekToPacket(SInt64 packetNumber); 350 SInt64 TellPacket() const { return mPacketMark; } // will be imprecise if SeekToFrame was called 351 352 void SetConverterChannelLayout(bool output, const CAAudioChannelLayout &layout); 353 void WritePacketsFromCallback( 354 AudioConverterComplexInputDataProc inInputDataProc, 355 void * inInputDataProcUserData); 356 // will use I/O buffer size 357 void InitFileMaxPacketSize(); 358 void FileFormatChanged(const FSRef *parentDir=0, CFStringRef filename=0, AudioFileTypeID filetype=0); 359 360 void GetExistingFileInfo(); 361 void FlushEncoder(); 362 void CloseConverter(); 363 void UpdateClientMaxPacketSize(); 364 void AllocateBuffers(bool okToFail=false); 365 SInt64 PacketToFrame(SInt64 packet) const; 366 SInt64 FrameToPacket(SInt64 inFrame) const; 367 368 static OSStatus ReadInputProc( AudioConverterRef inAudioConverter, 369 UInt32* ioNumberDataPackets, 370 AudioBufferList* ioData, 371 AudioStreamPacketDescription** outDataPacketDescription, 372 void* inUserData); 373 374 static OSStatus WriteInputProc( AudioConverterRef inAudioConverter, 375 UInt32* ioNumberDataPackets, 376 AudioBufferList* ioData, 377 AudioStreamPacketDescription** outDataPacketDescription, 378 void* inUserData); 379// _______________________________________________________________________________________ 380private: 381 382 // the file 383 FSRef mFSRef; 384 AudioFileID mAudioFile; 385 bool mOwnOpenFile; 386 bool mUseCache; 387 bool mFinishingEncoding; 388 enum { kClosed, kReading, kPreparingToCreate, kPreparingToWrite, kWriting } mMode; 389 390// SInt64 mNumberPackets; // in file's format 391 SInt64 mFileDataOffset; 392 SInt64 mPacketMark; // in file's format 393 SInt64 mFrameMark; // this may be offset from the start of the file 394 // by the codec's latency; i.e. our frame 0 could 395 // lie at frame 2112 of a decoded AAC file 396 SInt32 mFrame0Offset; 397 UInt32 mFramesToSkipFollowingSeek; 398 399 // buffers 400 UInt32 mIOBufferSizeBytes; 401 UInt32 mIOBufferSizePackets; 402 AudioBufferList mIOBufferList; // only one buffer -- USE ACCESSOR so it can be lazily initialized 403 bool mClientOwnsIOBuffer; 404 AudioStreamPacketDescription *mPacketDescs; 405 UInt32 mNumPacketDescs; 406 407 // formats/conversion 408 AudioConverterRef mConverter; 409 CAStreamBasicDescription mFileDataFormat; 410 CAStreamBasicDescription mClientDataFormat; 411 CAAudioChannelLayout mFileChannelLayout; 412 CAAudioChannelLayout mClientChannelLayout; 413 UInt32 mFileMaxPacketSize; 414 UInt32 mClientMaxPacketSize; 415 416 // cookie 417 Byte * mMagicCookie; 418 UInt32 mMagicCookieSize; 419 420 // for ReadPackets 421 UInt32 mMaxPacketsToRead; 422 423 // for WritePackets 424 UInt32 mWritePackets; 425 CABufferList * mWriteBufferList; 426 427#if CAAUDIOFILE_PROFILE 428 // performance 429 bool mProfiling; 430 UInt64 mTicksInConverter; 431 UInt64 mTicksInReadInConverter; 432 UInt64 mTicksInIO; 433 bool mInConverter; 434#endif 435 436#endif // CAAF_USE_EXTAUDIOFILE 437}; 438 439#endif // __CAAudioFile_h__