//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // AudioFilePlayer.h // // $Log: AudioFilePlayer.h,v $ // Revision 1.12 2003/04/18 23:05:13 baron // Use AudioFileReadPackets() in the special case of short files that are read entirely into memory. // // Revision 1.11 2003/04/18 17:37:43 baron // Make play file code work for aac. // // Revision 1.10 2003/04/09 22:33:11 baron // Pass audio data around by packets instead of bytes. // // Revision 1.9 2003/03/13 22:11:33 baron // Remove V1 code. Replace usage of AudioFile Read/WriteByte APIs with the Read/WritePacket versions. // // Revision 1.8 2002/06/23 22:17:20 bills // fix print // // Revision 1.7 2002/06/18 06:09:43 bills // change to render proc for V2 units // // Revision 1.6 2002/06/10 00:53:05 bills // cleanup defines for auv2 // // Revision 1.5 2002/06/02 04:38:23 bills // tweaks to now fully support v1 or v2 audio unit // // Revision 1.4 2002/06/01 23:58:19 bills // first pass at v2 units // // Revision 1.3 2002/05/19 23:23:23 bills // cleanup header // // Revision 1.2 2002/05/18 03:46:21 bills // add some additional API // // Revision 1.1 2002/05/18 01:19:47 bills // new location // // Revision 1.1 2002/05/17 07:56:45 bills // new dir loc // // Revision 1.6 2002/05/17 07:48:05 bills // Add FilePlay "C" API // // Revision 1.5 2002/05/16 09:22:09 bills // add notifications for file underruns // // Revision 1.4 2002/05/16 09:07:13 bills // use a single read thread for files // // Revision 1.3 2002/05/15 07:31:08 bills // add GetFileFormat call // // Revision 1.2 2002/05/15 06:21:59 bills // now use AudioConverter to do file reading // // Revision 1.1 2002/05/14 08:12:23 bills // initial checkin // // // General class for playing back a file //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #ifndef __AudioFilePlayer_H__ #define __AudioFilePlayer_H__ #include #include #include #include "AudioFilePlay.h" #define THROW_RESULT(str) \ if (result) { \ printf ("Error:%s=0x%lX,%ld,%s\n\n", \ str,result, result, (char*)&result); \ throw result; \ } typedef void (*AudioFileManagerErrorNotification)(void * inRefCon, OSStatus inErrorCode); class AudioFileManager; #pragma mark __________ AudioFilePlayer class AudioFilePlayer { public: AudioFilePlayer (const FSRef &inFileRef); ~AudioFilePlayer(); void SetDestination (AudioUnit &inDestUnit, int inBusNumber); void SetNotifier (AudioFilePlayNotifier inNotifier, void *inRefCon) { mNotifier = inNotifier; mRefCon = inRefCon; } void Connect(); void Disconnect(); void DoNotification (OSStatus inError) const; bool IsConnected () const { return mConnected; } void SetLooping (bool inLoop); bool IsLooping () const; UInt32 GetBusNumber () const { return mBusNumber; } AudioUnit GetDestUnit () const { return mPlayUnit; } AudioConverterRef GetAudioConverter() const { return mConverter; } void Print() const { CAShow (mAudioFileID); printf ("Destination Bus:%ld\n", GetBusNumber()); printf ("Is Connected:%s\n", (IsConnected() ? "true" : "false")); printf ("Using Reader Thread:%s\n", (mUsingReaderThread ? "true" : "false")); if (mConverter) CAShow (mConverter); printf ("- - - - - - - - - - - - - - \n"); } const AudioStreamBasicDescription& GetFileFormat() const { return mFileDescription; } private: AudioUnit mPlayUnit; UInt32 mBusNumber; AudioFileID mAudioFileID; AudioUnitInputCallback mInputCallback; AURenderCallbackStruct mRenderCallback; AudioStreamBasicDescription mFileDescription; bool mConnected; bool mUsingReaderThread; AudioFileManager* mAudioFileManager; AudioConverterRef mConverter; AudioFilePlayNotifier mNotifier; void* mRefCon; #pragma mark __________ Private_Methods void OpenFile (const FSRef& inRef, SInt64& outFileSize, SInt64& outPacketCount, UInt32& outMaxPacketSize); }; #pragma mark __________ AudioFileManager class AudioFileManager { public: AudioFileManager (AudioFilePlayer& inParent, AudioFileID inFile) : mParent (inParent), mAudioFileID (inFile), mFileBuffer (0), mIsLooping (false), mCurrentByteCountInBuffer(0), mCurrentPacketCountInBuffer(0), mPacketDescriptions(NULL) {} virtual ~AudioFileManager(); void Connect (AudioConverterRef inConverter) { mParentConverter = inConverter; DoConnect(); } // this method should NOT be called by an object of this class // as it is called by the parent's Disconnect() method virtual void Disconnect () {} void SetLooping (bool inLooping) { mIsLooping = inLooping; } bool IsLooping () const { return mIsLooping; } const AudioFileID& GetFileID() const { return mAudioFileID; } const char* GetFileBuffer () { return mFileBuffer; } const AudioFilePlayer& GetParent () const { return mParent; } protected: AudioFilePlayer& mParent; AudioConverterRef mParentConverter; const AudioFileID mAudioFileID; char* mFileBuffer; bool mIsLooping; OSStatus Render (AudioBuffer &ioData); OSStatus Render (AudioBufferList &ioData, UInt32 inNumFrames); virtual OSStatus GetFileData (void** inOutData, UInt32 *inOutDataSize, UInt32 *outPacketCount, AudioStreamPacketDescription **outPacketDescriptions) = 0; virtual void DoConnect () = 0; virtual void AfterRender () = 0; public: UInt32 mCurrentByteCountInBuffer; UInt32 mCurrentPacketCountInBuffer; AudioStreamPacketDescription* mPacketDescriptions; static OSStatus FileRenderProc (void *inRefCon, AudioUnitRenderActionFlags *inActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumFrames, AudioBufferList *ioData); static OSStatus ACComplexInputProc (AudioConverterRef inAudioConverter, UInt32* ioNumberDataPackets, AudioBufferList* ioData, AudioStreamPacketDescription** outDataPacketDescription, void* inUserData); }; #pragma mark __________ AudioFileData class AudioFileData : public AudioFileManager { public: AudioFileData ( AudioFilePlayer &inParent, AudioFileID &inFile, SInt64 inFileLength, SInt64 inPacketCount, UInt32 inMaxPacketSize, UInt32 inChunkSizeInPackets); protected: virtual void DoConnect (); virtual OSStatus GetFileData (void** inOutData, UInt32 *inOutDataSize, UInt32 *outPacketCount, AudioStreamPacketDescription **outPacketDescriptions); virtual void AfterRender (); private: bool mFirstTime; bool mShouldFinish; UInt32 mFileLength; }; struct FileThreadVariables : public AudioFileManager { const UInt32 mChunkSizeInPackets; const SInt64 mFileLength; const SInt64 mPacketCount; const UInt32 mMaxPacketSize; SInt64 mReadPacketPosition; bool mWriteToFirstBuffer; bool mFinishedReadingData; FileThreadVariables ( const UInt32 inChunkSizeInPackets, const SInt64 inFileLength, const SInt64 inPacketCount, UInt32 inMaxPacketSize, AudioFilePlayer &inParent, AudioFileID &inFile) : AudioFileManager (inParent, inFile), mChunkSizeInPackets (inChunkSizeInPackets), mFileLength (inFileLength), mPacketCount (inPacketCount), mMaxPacketSize (inMaxPacketSize), mReadPacketPosition (0), mWriteToFirstBuffer (false), mFinishedReadingData (false) {} virtual ~FileThreadVariables() {} }; #pragma mark __________ AudioFileReaderThread class AudioFileReaderThread : public FileThreadVariables { public: AudioFileReaderThread (AudioFilePlayer &inParent, AudioFileID &inFile, SInt64 inFileLength, SInt64 inPacketCount, UInt32 inMaxPacketSize, UInt32 inChunkSizeInPackets); virtual void Disconnect (); protected: virtual void DoConnect (); virtual OSStatus GetFileData ( void** inOutData, UInt32 *inOutDataSize, UInt32 *outPacketCount, AudioStreamPacketDescription **outPacketDescriptions); virtual void AfterRender (); private: bool mReadFromFirstBuffer; bool mLockUnsuccessful; bool mIsEngaged; int mNumTimesAskedSinceFinished; }; #endif