// Copyright (c) 2005-2009 Nokia Corporation and/or its subsidiary(-ies).
// All rights reserved.
// This component and the accompanying materials are made available
// under the terms of "Eclipse Public License v1.0"
// which accompanies this distribution, and is available
// at the URL "http://www.eclipse.org/legal/epl-v10.html".
//
// Initial Contributors:
// Nokia Corporation - initial contribution.
//
// Contributors:
//
// Description:
//

#ifndef __BTSBCFRAMEPARAMETERS_H__
#define __BTSBCFRAMEPARAMETERS_H__

/**
This class contains 6 SBC frame parameters: sampling frequency, block length, 
channel mode, allocation mode, subbands and bitpool. It can validate all the 
parameters, calculate frame length and bit rate.
@internalComponent
*/
class TSBCFrameParameters
	{
public:
	/**
	This enum list all the possible sampling frequency settings
	*/
	enum TSamplingFrequency
		{
		/**
		sampling frequency is 16000 Hz
		*/
		E16000Hz = 0,
		/**
		sampling frequency is 32000 Hz
		*/
		E32000Hz,
		/**
		sampling frequency is 44100 Hz
		*/
		E44100Hz,
		/**
		sampling frequency is 48000 Hz
		*/
		E48000Hz
		};

	/**
	This enum list all the possible block length settings
	*/
	enum TBlockLength
		{
		/**
		block length is 4, one frame contains 4 blocks of audio samples
		*/
		E4Blocks = 0,
		/**
		block length is 8, one frame contains 8 blocks of audio samples
		*/
		E8Blocks,
		/**
		block length is 12, one frame contains 12 blocks of audio samples
		*/
		E12Blocks,
		/**
		block length is 16, one frame contains 16 blocks of audio samples
		*/
		E16Blocks
		};

	/**
	This enum list all the possible channel mode settings
	*/
	enum TChannelMode
		{
		/**
		channel mode is Mono, in this mode,
		only one channel contains audio samples.
		*/
		EMono = 0,
		/**
		channel mode is Dual Channel, in this mode,
		it contains two seperate mono audio samples.
		*/
		EDualChannel,
		/**
		channel mode is Stereo, in this mode,
		it contains stereo audio samples.
		*/
		EStereo,
		/**
		channel mode is Joint Stereo, in this mode,
		the left channel stores half of sum of both channels, 
		the right channel stores half of difference of both channels. 
		*/
		EJointStereo
		};

	/**
	This enum list all the possible allocation method settings
	*/
	enum TAllocationMethod
		{
		/**
		allocation method is Loudness, in this mode, 
		the bit allocation calculation uses Table offset4 or offset8 as well as scale factors
		*/
		ELoudness = 0,
		/**
		allocation method is SNR, in this mode,
		bit allocation only uses scale factors
		*/
		ESNR
		};

	/**
	This enum list all the possible subbands settings
	*/
	enum TSubbands
		{
		/**
		subbands is 4, each channel contains 4 subbands in each block, 
		each subband contains one sample
		*/
		E4Subbands = 0,
		/**
		subbands is 8, each channel contains 8 subbands in each block, 
		each subband contains one sample
		*/
		E8Subbands
		};
		
public:
	inline TSBCFrameParameters();
	
	inline void Reset();

	inline TUint8 	SamplingFrequencyEnum() const;
	inline TUint	SamplingFrequencyHz() const;
	inline void		SetSamplingFrequency(TSamplingFrequency aSamplingFrequency);
	
	inline TUint8	BlockLength() const;
	inline void		SetBlockLength(TBlockLength aBlockLength);
	
	inline TUint8 	ChannelMode() const;
	inline TUint8	Channels() const;
	inline void 	SetChannelMode(TChannelMode aChannelMode);
	
	inline TUint8 	AllocationMethod() const;
	inline void 	SetAllocationMethod(TAllocationMethod aAllocationMethod);
	
	inline TUint8	SubbandsEnum() const;
	inline TUint8	Subbands() const;
	inline void 	SetSubbands(TSubbands aSubbands);
	
	inline TUint8	Bitpool() const;
	inline void		SetBitpool(TUint8 aBitpool);
	
	inline TUint8	Parameters() const;
	inline TInt 	Validate() const;

	inline TUint 	CalcFrameLength() const;
	inline TUint 	CalcBitRate(TUint aFrameLength) const;

private:
	TUint8 	iParameters;
	TUint8 	iBitpool;
	};

/**
The minimum SBC bitpool value is 2 
*/	
const TUint8 KSBCMinBitpoolValue = 2;
/**
The maximum SBC bitpool value is 250 
*/	
const TUint8 KSBCMaxBitpoolValue = 250;

/**
The sampling frequency bits mask is 0b11, 2 bits
*/	
const TUint8 KSBCSampFreqBitsMask  = 0x3;
/**
The bit offset of sampling frequency field in TSBCFrameParameters::iParameters is 6
*/
const TUint8 KSBCSampFreqBitOffset = 6;

/**
The block length bits mask is 0b11, 2 bits
*/	
const TUint8 KSBCBlckLengBitsMask  = 0x3;
/**
The bit offset of block length field in TSBCFrameParameters::iParameters is 4
*/
const TUint8 KSBCBlckLengBitOffset = 4;

/**
The block length bits mask is 0b11, 2 bits
*/	
const TUint8 KSBCChnlModeBitsMask  = 0x3;
/**
The bit offset of block length field in TSBCFrameParameters::iParameters is 2
*/
const TUint8 KSBCChnlModeBitOffset = 2;

/**
The block length bits mask is 0b01, 1 bit
*/	
const TUint8 KSBCAllcMthdBitsMask  = 0x1;
/**
The bit offset of block length field in TSBCFrameParameters::iParameters is 1
*/
const TUint8 KSBCAllcMthdBitOffset = 1;

/**
The block length bits mask is 0b01, 1 bit
*/	
const TUint8 KSBCSubbandsBitsMask  = 0x1;
/**
The bit offset of block length field in TSBCFrameParameters::iParameters is 0
*/
const TUint8 KSBCSubbandsBitOffset = 0;

/**
Constructor
@internalComponent
*/
inline TSBCFrameParameters::TSBCFrameParameters() : iParameters(0), iBitpool(0)
	{
	}
	
/**
This function reset all the parameters
@internalComponent
*/
inline void TSBCFrameParameters::Reset()
	{
	iParameters = 0;
	iBitpool = 0;
	}
	
/**
This function gets the sampling frequency enum value
@internalComponent
@return enum value of sampling frequency
*/
inline TUint8 TSBCFrameParameters::SamplingFrequencyEnum() const
	{
	return static_cast<TUint8>( (iParameters >> KSBCSampFreqBitOffset) & KSBCSampFreqBitsMask);
	}
	
/**
This function gets the sampling frequency value in Hz
@internalComponent
@return samplinng frequency value in Hz
*/
inline TUint TSBCFrameParameters::SamplingFrequencyHz() const
	{
	switch (SamplingFrequencyEnum() )
		{
		case E16000Hz:
			return 16000;
			
		case E32000Hz:
			return 32000;
			
		case E44100Hz:
			return 44100;
			
		case E48000Hz:
			return 48000;
		}
	return 0;
	}

/**
This function sets the sampling frequency value
@internalComponent
@param aSampFreq
New sampling frequency enum value to set
*/
inline void TSBCFrameParameters::SetSamplingFrequency(TSamplingFrequency aSampFreq)
	{
	// clear sampling frequency bits
	iParameters &= ~(KSBCSampFreqBitsMask << KSBCSampFreqBitOffset);
	// set new sampling frequency bits
	iParameters |= ( (aSampFreq & KSBCSampFreqBitsMask) << KSBCSampFreqBitOffset);
	}

/**
This function gets the block length value
@internalComponent
@return number of blocks in one frame
*/
inline TUint8 TSBCFrameParameters::BlockLength() const
	{
	switch ( (iParameters >> KSBCBlckLengBitOffset) & KSBCBlckLengBitsMask)
		{
		case E4Blocks:
			return 4;
			
		case E8Blocks:
			return 8;
			
		case E12Blocks:
			return 12;
			
		case E16Blocks:
			return 16;
		}
	return 0;
	}

/**
This function sets the block length value
@internalComponent
@param aBlockLen
New block length value to set
*/
inline void TSBCFrameParameters::SetBlockLength(TBlockLength aBlockLen)
	{
	// clear block length bits
	iParameters &= ~(KSBCBlckLengBitsMask << KSBCBlckLengBitOffset);
	// set new block length bits
	iParameters |= ( (aBlockLen & KSBCBlckLengBitsMask) << KSBCBlckLengBitOffset);
	}

/**
This function gets the channel mode enum value
@internalComponent
@return channel mode enum value
*/
inline TUint8 TSBCFrameParameters::ChannelMode() const
	{
	return static_cast<TUint8>( (iParameters >> KSBCChnlModeBitOffset) & KSBCChnlModeBitsMask);
	}

/**
This function gets number of channels
@internalComponent
@return number of channels
*/
inline TUint8 TSBCFrameParameters::Channels() const
	{
	switch (ChannelMode() )
		{
		case EMono:
			return 1;
			
		case EDualChannel:
		case EStereo:
		case EJointStereo:
			return 2;
		}
	return 0;
	}
	
/**
This function sets the channel mode enum value
@internalComponent
@param aChnlMode
New channel mode enum value to set
*/
inline void TSBCFrameParameters::SetChannelMode(TChannelMode aChnlMode)
	{
	// clear channel mode bits
	iParameters &= ~(KSBCChnlModeBitsMask << KSBCChnlModeBitOffset);
	// set new channel mode bits
	iParameters |= ( (aChnlMode & KSBCChnlModeBitsMask) << KSBCChnlModeBitOffset);
	}

/**
This function gets the allocation method enum value
@internalComponent
@return allocation method enum value
*/
inline TUint8 TSBCFrameParameters::AllocationMethod() const
	{
	return static_cast<TUint8>( (iParameters >> KSBCAllcMthdBitOffset) & KSBCAllcMthdBitsMask);
	}

/**
This function sets the channel mode enum value
@internalComponent
@param aAllocMethod
New channel mode enum value to set
*/
inline void TSBCFrameParameters::SetAllocationMethod(TAllocationMethod aAllocMethod)
	{
	// clear allocation method bits
	iParameters &= ~(KSBCAllcMthdBitsMask << KSBCAllcMthdBitOffset);
	// set new allocation method bits
	iParameters |= ( (aAllocMethod & KSBCAllcMthdBitsMask) << KSBCAllcMthdBitOffset);
	}		

/**
This function gets the subbands enum value
@internalComponent
@return subbands enum value
*/
inline TUint8 TSBCFrameParameters::SubbandsEnum() const
	{
	return static_cast<TUint8>( (iParameters >> KSBCSubbandsBitOffset) & KSBCSubbandsBitsMask);
	}

/**
This function gets the subbands value
@internalComponent
@return subbands value, i.e 4, 8
*/
inline TUint8 TSBCFrameParameters::Subbands() const
	{
	switch (SubbandsEnum() )
		{
		case E4Subbands:
			return 4;
			
		case E8Subbands:
			return 8;
		}
	return 0;
	}
	
/**
This function sets the subbands enum value
@internalComponent
@param aSubbands
New subbands enum value to set
*/
inline void TSBCFrameParameters::SetSubbands(TSubbands aSubbands)
	{
	// clear subbands bits
	iParameters &= ~(KSBCSubbandsBitsMask << KSBCSubbandsBitOffset);
	// set new subbands bits
	iParameters |= ( (aSubbands & KSBCSubbandsBitsMask) << KSBCSubbandsBitOffset);
	}		

/**
This function gets the bitpool value
@internalComponent
@return bitpool value
*/
inline TUint8 TSBCFrameParameters::Bitpool() const
	{
	return iBitpool;
	}

/**
This function sets the bitpool enum value
@internalComponent
@param aSubbands
New bitpool enum value to set
*/
inline void TSBCFrameParameters::SetBitpool(TUint8 aBitpool)
	{
	iBitpool = aBitpool;
	}

/**
This function gets the 5 parameters (except bitpool) byte value
@internalComponent
@return 5 parameters byte value
*/
inline TUint8 TSBCFrameParameters::Parameters() const
	{
	return iParameters;
	}
	
/**
This function checks the bitpool value according to:
1. bitpool >= 2 and bitpool <= 250
2. bitpool <= 16 * subbands for Mono and Dual Channel,
   bitpool <= 32 * subbands for Stereo and Joint Stereo 
3. results in bit_rate <= 320 kbps for Mono
   results in bit_rate <= 512 kpbs for two-channel modes
@internalComponent
@return -1 if invalid; 0 if valid
*/
inline TInt TSBCFrameParameters::Validate() const
	{
	if (iBitpool < KSBCMinBitpoolValue || iBitpool > KSBCMaxBitpoolValue)
		{
		return -1;
		}
		
	const TUint16 numSubbands = Subbands(); // use 16 bits to avoid overflow
	const TUint8 channelMode = ChannelMode();
	
	if (channelMode == EMono || channelMode == EDualChannel)
		{
		// bitpool <= 16 * subbands, for Mono and Dual_Channel modes
		if (iBitpool > (numSubbands << 4) )
			{
			return -1;
			}
		}
	else
		{
		// bitpool <= 32 * subbands, for Stereo and Joint_Stereo modes
		if (iBitpool > (numSubbands << 5) )
			{
			return -1;
			}
		}
	
	if (channelMode == EMono)
		{
		// bit rate <= 320kbps for Mono mode
		if (CalcBitRate(CalcFrameLength() ) > 320)
			{
			return -1;
			}
		}
	else
		{
		// bit rate <= 512kpbs for two-channels modes
		if (CalcBitRate(CalcFrameLength() ) > 512)
			{
			return -1;
			}
		}
	
	return 0;
	}

/**
This function calculates the frame length value according to:
1. for MONO or DUAL_CHANNEL
   frame_len = 4 + (4 * subbands * channels) / 8 + ceil(blocks * channels * bitpool / 8)
2. for STEREO
   frame_len = 4 + (4 * subbands * channels) / 8 + ceil(blocks * bitpool / 8)
3. for JOINT_STEREO
   frame_len = 4 + (4 * subbands * channels) / 8 + ceil((subbands + blocks * bitpool) / 8)
ceil(), taking the upper integer value
@internalComponent
@return frame length value
*/
inline TUint TSBCFrameParameters::CalcFrameLength() const
	{
	TUint temp = 0;
	switch (ChannelMode() )
		{
		case EMono:
			temp = BlockLength() * Bitpool(); // blocks * bitpool
			break;
			
		case EDualChannel:
			temp = (BlockLength() * Bitpool() ) << 1; // blocks * bitpool * 2
			break;
			
		case EStereo:
			temp = BlockLength() * Bitpool(); // blocks * bitpool
			break;
			
		case EJointStereo:
			temp = Subbands() + BlockLength() * Bitpool(); // subbands + blocks * bitpool
			break;
			
		default:
			User::Panic(_L("Invalid channel mode"), KErrNotSupported);
			break;
		}
		
	TUint frameLen = 4 + ( (Subbands() * Channels() ) >> 1) + (temp >> 3);
	if (temp & 0x7)
		{
		frameLen++;
		}
		
	return frameLen;
	}

/**
This function calculates the bit rate value according to:
	bit_rate = 8 * frame_len * sampling_freq / subbands / blocks
@internalComponent
@return bit rate value in kHz
*/
inline TUint TSBCFrameParameters::CalcBitRate(TUint aFrameLen) const
	{
	return (aFrameLen << 3) * SamplingFrequencyHz() / (Subbands() * BlockLength() * 1000);
	}

#endif // __BTSBCFRAMEPARAMETERS_H__

