/*============================================================================= CAAudioFileRecorder.cpp $Log: CAAudioFileRecorder.cpp,v $ Revision 1.5 2004/10/15 17:10:34 dwyatt CAAudioFile rewrite to use ExtAudioFile (changeable via compile flag in CAAudioFile.h) Revision 1.4 2004/05/27 19:51:54 dwyatt reinstate SetFile methods which allowed wrapping an existing CAAudioFile Revision 1.3 2004/05/26 00:36:02 dwyatt track change to CABufferQueue; writer/recorder now create their own CAAudioFile's from scratch instead of wrapping the client's [3666988] Revision 1.2 2004/01/27 01:42:42 dwyatt remove cruft Revision 1.1 2004/01/14 00:08:09 dwyatt moved from Source/Tests/AudioFileUtility/Utility Revision 1.3 2003/10/21 23:39:31 dwyatt fix order of input unit initialization, use default input device Revision 1.2 2003/10/15 00:27:30 dwyatt refactor on top of CABufferQueue Revision 1.1 2003/10/09 23:19:37 dwyatt initial checkin created Tue Sep 30 2003, Doug Wyatt Copyright (c) 2003 Apple Computer, Inc. All Rights Reserved $NoKeywords: $ =============================================================================*/ #include "CAAudioFileRecorder.h" #include "CAXException.h" CAAudioFileRecorder::CAAudioFileRecorder(int nBuffers, UInt32 bufferSizeFrames) : CAAudioFileWriter(nBuffers, bufferSizeFrames), mInputUnit(NULL), mAudioInputPtrs(NULL) { // open input unit Component comp; ComponentDescription desc; 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 input unit"); XThrowIfError(OpenAComponent(comp, &mInputUnit), "open audio input unit"); UInt32 enableIO; UInt32 propSize; enableIO = 0; XThrowIfError(AudioUnitSetProperty(mInputUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output, 0, &enableIO, sizeof(enableIO)), "failed to disable output"); enableIO = 1; XThrowIfError(AudioUnitSetProperty(mInputUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, 1, &enableIO, sizeof(enableIO)), "failed to enable input"); // select the default input device propSize = sizeof(AudioDeviceID); AudioDeviceID inputDevice; XThrowIfError( AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice, &propSize, &inputDevice), "failed to get default input device"); XThrowIfError( AudioUnitSetProperty(mInputUnit, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, 0, &inputDevice, sizeof(inputDevice)), "failed to select input device"); // set render callback AURenderCallbackStruct input; input.inputProc = InputProc; input.inputProcRefCon = this; XThrowIfError(AudioUnitSetProperty( mInputUnit, kAudioOutputUnitProperty_SetInputCallback, kAudioUnitScope_Global, 0, &input, sizeof(input)), "connect input proc to output unit"); XThrowIfError(AudioUnitInitialize(mInputUnit), "initialize audio input unit"); // get the hardware format propSize = sizeof(mInputDataFormat); XThrowIfError(AudioUnitGetProperty(mInputUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 1, &mInputDataFormat, &propSize), "couldn't get input unit's stream format"); } CAAudioFileRecorder::~CAAudioFileRecorder() { if (mInputUnit) CloseComponent(mInputUnit); delete mAudioInputPtrs; } void CAAudioFileRecorder::SetFile(const FSRef &parentFSRef, CFStringRef filename, AudioFileTypeID filetype, const CAStreamBasicDescription &dataFormat, const CAAudioChannelLayout *layout) { delete mAudioInputPtrs; mAudioInputPtrs = NULL; CAStreamBasicDescription fileDataFormat = dataFormat; if (fileDataFormat.mSampleRate == 0.) fileDataFormat.mSampleRate = mInputDataFormat.mSampleRate; CAAudioFileWriter::SetFile(parentFSRef, filename, filetype, fileDataFormat, layout); const CAStreamBasicDescription &fmt = GetFile().GetClientDataFormat(); XThrowIfError(AudioUnitSetProperty( mInputUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 1, (void *)&fmt, sizeof(AudioStreamBasicDescription)), "set audio input format"); GetFile().SetIOBufferSizeBytes(GetBufferSizeFrames() * fmt.mBytesPerFrame); mAudioInputPtrs = CABufferList::New("audio input ptrs", fmt); } /* void CAAudioFileRecorder::SetFile(AudioFileID fileID) { delete mAudioInputPtrs; mAudioInputPtrs = NULL; CAAudioFileWriter::SetFile(fileID, mInputDataFormat.mSampleRate); const CAStreamBasicDescription &fmt = GetFile().GetClientDataFormat(); XThrowIfError(AudioUnitSetProperty( mInputUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 1, (void *)&fmt, sizeof(AudioStreamBasicDescription)), "set audio input format"); GetFile().SetIOBufferSize(GetBufferSizeFrames() * fmt.mBytesPerFrame); mAudioInputPtrs = CABufferList::New("audio input ptrs", fmt); } */ void CAAudioFileRecorder::Start() { CAAudioFileWriter::Start(); XThrowIfError(AudioOutputUnitStart(mInputUnit), "start audio input unit"); } void CAAudioFileRecorder::Stop() { XThrowIfError(AudioOutputUnitStop(mInputUnit), "stop audio input unit"); CAAudioFileWriter::Stop(); } OSStatus CAAudioFileRecorder::InputProc( void * inRefCon, AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp * inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList * ioData) { CAAudioFileRecorder *This = static_cast(inRefCon); AudioUnitRenderActionFlags flags = 0; AudioBufferList *abl = &This->mAudioInputPtrs->GetModifiableBufferList(); OSStatus err = AudioUnitRender(This->mInputUnit, &flags, inTimeStamp, 1, inNumberFrames, abl); if (err) return err; This->PushBuffer(inNumberFrames, abl); return noErr; }