/*============================================================================= CAAudioFilePlayer.cpp $Log: CAAudioFilePlayer.cpp,v $ Revision 1.3 2004/10/15 17:10:34 dwyatt CAAudioFile rewrite to use ExtAudioFile (changeable via compile flag in CAAudioFile.h) Revision 1.2 2004/09/30 21:06:04 jcm10 add a fallback if the default output unit can't be found Revision 1.1 2004/01/14 00:08:09 dwyatt moved from Source/Tests/AudioFileUtility/Utility Revision 1.11 2003/12/04 00:59:02 dwyatt refactoring Revision 1.10 2003/10/15 00:27:30 dwyatt refactor on top of CABufferQueue Revision 1.9 2003/10/09 23:23:13 dwyatt refactor/cleanup to support CAAudioFileRecorder Revision 1.8 2003/09/11 00:48:31 dwyatt Stop/Start are now virtual overrides Revision 1.7 2003/08/23 04:52:57 dwyatt track change to CAAudioFile (layout) Revision 1.6 2003/08/04 23:44:12 dwyatt refactoring for subclassing Revision 1.5 2003/07/25 23:29:12 dwyatt use constant strings for operations in CAXException Revision 1.4 2003/07/10 17:53:42 dwyatt don't apply invalid layouts, don't throw if applying a layout fails Revision 1.3 2003/07/09 19:13:28 dwyatt sync with base class changes Revision 1.2 2003/06/30 21:51:13 dwyatt trap exceptions in SeekToPacket Revision 1.1 2003/06/23 23:07:37 dwyatt initial checkin created Thu Jun 19 2003, Doug Wyatt Copyright (c) 2003 Apple Computer, Inc. All Rights Reserved $NoKeywords: $ =============================================================================*/ #include "CAAudioFilePlayer.h" #include "CAXException.h" CAAudioFilePlayer::CAAudioFilePlayer(int nBuffers, UInt32 bufferSizeBytes) : CAAudioFileReader(nBuffers, bufferSizeBytes), mOutputUnit(NULL) { // open output unit Component comp; ComponentDescription desc; desc.componentType = kAudioUnitType_Output; desc.componentSubType = kAudioUnitSubType_DefaultOutput; desc.componentManufacturer = kAudioUnitManufacturer_Apple; desc.componentFlags = 0; desc.componentFlagsMask = 0; comp = FindNextComponent(NULL, &desc); // if we can't find the default one, look explicitly for AUHAL if(comp == NULL) { desc.componentType = kAudioUnitType_Output; desc.componentSubType = kAudioUnitSubType_HALOutput; desc.componentManufacturer = kAudioUnitManufacturer_Apple; desc.componentFlags = 0; desc.componentFlagsMask = 0; comp = FindNextComponent(NULL, &desc); } XThrowIf(comp == NULL, -1, "find audio output unit"); XThrowIfError(OpenAComponent(comp, &mOutputUnit), "open audio output unit"); XThrowIfError(AudioUnitInitialize(mOutputUnit), "initialize audio output unit"); } CAAudioFilePlayer::~CAAudioFilePlayer() { if (mOutputUnit) CloseComponent(mOutputUnit); } void CAAudioFilePlayer::SetFile(const FSRef &inFile) { Stop(); CAAudioFileReader::SetFile(inFile); SetupChannelMapping(); } void CAAudioFilePlayer::SetupChannelMapping() { // set render callback AURenderCallbackStruct input; input.inputProc = InputProc; input.inputProcRefCon = this; XThrowIfError(AudioUnitSetProperty( mOutputUnit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Global, 0, &input, sizeof(input)), "connect input proc to output unit"); const CAStreamBasicDescription &fmt = GetFile().GetClientDataFormat(); XThrowIfError(AudioUnitSetProperty( mOutputUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, (void *)&fmt, sizeof(AudioStreamBasicDescription)), "set audio output format"); const CAAudioChannelLayout &layoutObj = GetFile().GetFileChannelLayout(); if (layoutObj.IsValid()) { const AudioChannelLayout *layout = layoutObj; /*OSStatus err =*/ AudioUnitSetProperty( mOutputUnit, kAudioUnitProperty_AudioChannelLayout, kAudioUnitScope_Input, 0, layout, layoutObj.Size()); // $$$ FIXME: why does this fail sometimes? } } void CAAudioFilePlayer::Start() { if (IsRunning()) Stop(); if (ReachedEndOfStream()) SetCurrentPosition(0.); CAAudioFileReader::Start(); XThrowIfError(AudioOutputUnitStart(mOutputUnit), "start audio output unit"); } void CAAudioFilePlayer::Stop() { if (IsRunning()) { XThrowIfError(AudioOutputUnitStop(mOutputUnit), "stop audio output unit"); CAAudioFileReader::Stop(); } } void CAAudioFilePlayer::SetVolume(double volume) { AudioUnitSetParameter(mOutputUnit, kHALOutputParam_Volume, kAudioUnitScope_Global, 0, volume, 0); } OSStatus CAAudioFilePlayer::GetPlayBuffer( UInt32 inNumberFrames, AudioBufferList * ioData) { UInt32 nFrames = inNumberFrames; PullBuffer(nFrames, ioData); // printf("read %ld frames\n", nFrames); if (nFrames < inNumberFrames) { AudioBuffer *buf = ioData->mBuffers; UInt32 bytesPerFrame = buf->mNumberChannels * sizeof(Float32); for (UInt32 i = 0; i < ioData->mNumberBuffers; ++i, ++buf) { memset((Byte *)buf->mData + nFrames * bytesPerFrame, 0, (inNumberFrames - nFrames) * bytesPerFrame); } } return noErr; } OSStatus CAAudioFilePlayer::InputProc( void * inRefCon, AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp * inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList * ioData) { CAAudioFilePlayer *This = static_cast(inRefCon); return This->GetPlayBuffer(inNumberFrames, ioData); }