/*=============================================================================
	CAAudioUnitOutputCapturer.h
	
	$Log: CAAudioUnitOutputCapturer.h,v $
	Revision 1.3  2006/01/19 20:03:29  dwyatt
	set a client format on the ExtAudioFile
	
	Revision 1.2  2006/01/18 22:42:17  dwyatt
	add an example
	
	Revision 1.1  2006/01/18 22:36:54  dwyatt
	initial checkin
	
	created 1/18/06, Doug Wyatt
	Copyright (c) 2006 Apple Computer, Inc.  All Rights Reserved

	$NoKeywords: $
=============================================================================*/

#ifndef __CAAudioUnitOutputCapturer_h__
#define __CAAudioUnitOutputCapturer_h__

#include <AudioToolbox/ExtendedAudioFile.h>

/*
	Class to capture output from an AudioUnit for analysis.

	example:

	CFURL fileurl = CFURLCreateWithFileSystemPath(NULL, CFSTR("/tmp/recording.caf"), kCFURLPOSIXPathStyle, false);

	CAAudioUnitOutputCapturer captor(someAU, fileurl, 'caff', anASBD);

	{
	captor.Start();
	...
	captor.Stop();
	} // can repeat

	captor.Close(); // can be omitted; happens automatically from destructor
*/

class CAAudioUnitOutputCapturer {
public:
	CAAudioUnitOutputCapturer(AudioUnit au, CFURLRef outputFileURL, AudioFileTypeID fileType, const AudioStreamBasicDescription &format) :
		mFileOpen(false),
		mClientFormatSet(false),
		mAudioUnit(au),
		mExtAudioFile(NULL)
	{
		FSRef fsref;
		CFURLRef directory = CFURLCreateCopyDeletingLastPathComponent(NULL, outputFileURL);
		CFStringRef filename = CFURLCopyLastPathComponent(outputFileURL);
		if (CFURLGetFSRef(directory, &fsref)) {
			OSStatus err = ExtAudioFileCreateNew(&fsref, filename, fileType, &format, NULL, &mExtAudioFile);
			if (!err)
				mFileOpen = true;
		}
		CFRelease(directory);
		CFRelease(filename);
	}
	
	void	Start() {
		if (mFileOpen) {
			if (!mClientFormatSet) {
				AudioStreamBasicDescription clientFormat;
				UInt32 size = sizeof(clientFormat);
				AudioUnitGetProperty(mAudioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 0, &clientFormat, &size);
				ExtAudioFileSetProperty(mExtAudioFile, kExtAudioFileProperty_ClientDataFormat, size, &clientFormat);
				mClientFormatSet = true;
			}
			
			ExtAudioFileWriteAsync(mExtAudioFile, 0, NULL);	// initialize async writes
			AudioUnitAddRenderNotify(mAudioUnit, RenderCallback, this);
		}
	}
	
	void	Stop() {
		if (mFileOpen)
			AudioUnitRemoveRenderNotify(mAudioUnit, RenderCallback, this);
	}
	
	void	Close() {
		if (mExtAudioFile) {
			ExtAudioFileDispose(mExtAudioFile);
			mExtAudioFile = NULL;
		}
	}
	
	~CAAudioUnitOutputCapturer() {
		Close();
	}

private:
	static OSStatus RenderCallback(	void *							inRefCon,
									AudioUnitRenderActionFlags *	ioActionFlags,
									const AudioTimeStamp *			inTimeStamp,
									UInt32							inBusNumber,
									UInt32							inNumberFrames,
									AudioBufferList *				ioData)
	{
		if (inBusNumber == 0 && (*ioActionFlags & kAudioUnitRenderAction_PostRender)) {
			CAAudioUnitOutputCapturer *This = (CAAudioUnitOutputCapturer *)inRefCon;
			ExtAudioFileWriteAsync(This->mExtAudioFile, inNumberFrames, ioData);
		}
		return noErr;
	}
	
	bool				mFileOpen;
	bool				mClientFormatSet;
	AudioUnit			mAudioUnit;
	ExtAudioFileRef		mExtAudioFile;
};

#endif // __CAAudioUnitOutputCapturer_h__
