/*=============================================================================
	CAAudioChannelLayout.h

	$Log: CAAudioChannelLayout.h,v $
	Revision 1.17  2005/01/06 01:48:44  dwyatt
	gcc4 / offsetof
	
	Revision 1.16  2004/08/11 17:59:38  jcm10
	protect the HAL from inadvertant includes of CoreServices
	
	Revision 1.15  2003/12/16 22:59:29  dwyatt
	Windows compile
	
	Revision 1.14  2003/12/02 00:15:46  bills
	some fixes for ref counting thread-safe-ness
	
	Revision 1.13  2003/11/20 22:56:53  dwyatt
	__COREAUDIO_USE_FLAT_INCLUDES__
	
	Revision 1.12  2003/08/26 09:27:21  dwyatt
	fix commenting
	
	Revision 1.11  2003/07/09 19:06:53  dwyatt
	cleanup - don't fill out channel descriptions based on layout tags
	
	Revision 1.10  2003/07/08 21:44:12  dwyatt
	inline some tiny methods for efficiency
	
	Revision 1.9  2003/07/08 06:24:57  bills
	add a size field
	
	Revision 1.8  2003/07/07 23:34:20  bills
	public default constructor
	
	Revision 1.7  2003/07/07 21:50:38  dwyatt
	more refactoring
	
	Revision 1.6  2003/07/07 18:36:45  bills
	Add Save/Restore
	
	Revision 1.5  2003/06/21 02:25:30  bills
	NumberChannels test is now complete
	
	Revision 1.4  2003/06/02 19:25:15  bills
	tweaks
	
	Revision 1.3  2003/05/25 21:55:43  bills
	add Print method
	
	Revision 1.2  2003/05/25 02:43:32  bills
	add object semantics
	
	Revision 1.1  2003/05/04 00:00:16  jcm10
	first checked in
	
	Revision 0.0  Sat May 03 2003 10:08:57 US/Pacific  moorf
	Created
		
	$NoKeywords: $
=============================================================================*/
#if !defined(__CAAudioChannelLayout_h__)
#define __CAAudioChannelLayout_h__

//=============================================================================
//	Includes
//=============================================================================

//	System Includes
#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__)
	#include <CoreAudio/CoreAudioTypes.h>
	#include <CoreFoundation/CoreFoundation.h>
#else
	#include <CoreAudioTypes.h>
	#include <CoreFoundation.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#if !HAL_Build
	#include "CAReferenceCounted.h"
#endif

//=============================================================================
//	CAAudioChannelLayout
//=============================================================================

bool	operator== (const AudioChannelLayout &x, const AudioChannelLayout &y);

extern "C" void 	CAShowAudioChannelLayout (FILE* file, const AudioChannelLayout *layout);

class CAAudioChannelLayout
{
//	static Construction/Destruction
public:
	static AudioChannelLayout*	Create(UInt32 inNumberChannelDescriptions);
	static void					Destroy(AudioChannelLayout* inChannelLayout);
	static UInt32				CalculateByteSize(UInt32 inNumberChannelDescriptions) { 
									return offsetof(AudioChannelLayout, mChannelDescriptions) + inNumberChannelDescriptions * sizeof(AudioChannelDescription);
								}
	static void					SetAllToUnknown(AudioChannelLayout& outChannelLayout, UInt32 inNumberChannelDescriptions);
	static UInt32				NumberChannels(const AudioChannelLayout& inLayout);
	
#if !HAL_Build
// object methods	
public:
								CAAudioChannelLayout ();

								CAAudioChannelLayout (UInt32 inNumberChannels, bool inChooseSurround);
									// if inChooseSurround is false, then symmetrical speaker arrangements
									// are chosen in place of surround layouts if there is a choice
									// This call chooses layouts based on the expected defaults in 
									// AudioUnit usage
								CAAudioChannelLayout (AudioChannelLayoutTag inTag);
								CAAudioChannelLayout (const CAAudioChannelLayout &c);
								CAAudioChannelLayout (const AudioChannelLayout* inChannelLayout);
								~CAAudioChannelLayout();
	
	CAAudioChannelLayout&		operator= (const AudioChannelLayout* inChannelLayout);
	CAAudioChannelLayout&		operator= (const CAAudioChannelLayout& c);
	bool						operator== (const CAAudioChannelLayout &c) const;

	void						SetWithTag(AudioChannelLayoutTag inTag);

	bool						IsValid() const { return NumberChannels() > 0; }
	UInt32						Size() const { return mLayoutHolder ? mLayoutHolder->Size() : 0; }
	
	UInt32						NumberChannels() const { return NumberChannels(Layout()); }
	
	AudioChannelLayoutTag		Tag() const { return Layout().mChannelLayoutTag; }
	const AudioChannelLayout&	Layout() const { return mLayoutHolder->Layout(); }
	operator const AudioChannelLayout *() const { return &Layout(); }
	
	void						Print () const { Print (stdout); }
	void						Print (FILE* file) const;

	OSStatus					Save (CFPropertyListRef *outData) const;
	OSStatus					Restore (CFPropertyListRef &inData);
	
private:
	class ACLRefCounter : public CAReferenceCounted {
	public:
				ACLRefCounter (UInt32 inDataSize) 
				{ 
					if (inDataSize < offsetof(AudioChannelLayout, mChannelDescriptions))
						inDataSize = offsetof(AudioChannelLayout, mChannelDescriptions);
						
					mLayout = static_cast<AudioChannelLayout*>(malloc (inDataSize));
					memset (mLayout, 0, inDataSize);
					mByteSize = inDataSize;
				}
	
		const AudioChannelLayout & 	Layout() const { return *mLayout; }
		
		UInt32						Size () const { return mByteSize; }
		
	private:
		AudioChannelLayout 	*mLayout;
		UInt32				mByteSize;
		
			// only the constructors can change the actual state of the layout
		friend CAAudioChannelLayout::CAAudioChannelLayout (UInt32 inNumberChannels, bool inChooseSurround);
		friend OSStatus CAAudioChannelLayout::Restore (CFPropertyListRef &inData);
		friend CAAudioChannelLayout& CAAudioChannelLayout::operator= (const AudioChannelLayout* inChannelLayout);
		friend void CAAudioChannelLayout::SetWithTag(AudioChannelLayoutTag inTag);
		
		AudioChannelLayout * 	GetLayout() { return mLayout; }
		~ACLRefCounter() { if (mLayout) { free(mLayout); mLayout = NULL; } }
	
	private:
		ACLRefCounter () : mLayout(NULL) { }
		ACLRefCounter(const ACLRefCounter& c) : mLayout(NULL) { }
		ACLRefCounter& operator=(const ACLRefCounter& c) { return *this; }
	};
	
	ACLRefCounter				*mLayoutHolder;
#endif	//	HAL_Build

};

#endif
