/*
* 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:  Implementation for CBTSACStreamerController class. This class constructs and
*				 communicates with 'BT Audio Streamer' component to do RTP streaming.
*
*/


// INCLUDE FILES
#include "btsacStreamerController.h"
#include "debug.h"

// Subband codec-specific values
// in bluetoothAV.h
using namespace SymbianSBC;      


// CONSTANTS
_LIT(KBTAADLL, "btaudioadaptation.dll");
 
const TInt KRetryTimerDelay = 2000000;		// 2 seconds. If something fails, how soon should we retry. 
const TInt KStabilizationDelay = 2000000;	// 2 seconds. Wait this long after bitpool change then start mononitor packet drops again
const TInt KDataCollectDelay = 600000; 		// Time (600ms) to collect packet drop data

// All tables below have to formed such a way that highest max bitpool value has to be in position 0 and etc.
const TInt KMaxBitpoolValues[] = {59, 48, 40, 34}; // Max bitpool values
const TInt KDeviationValues[] = {1000, 100000, 300000, 300000}; // maximum time (ys) between first and last packet dropped event

const TInt KNumOfBitpoolValues = sizeof(KMaxBitpoolValues)/sizeof(TInt);
#define MAXBITPOOLVALUEMAX KMaxBitpoolValues[0]
#define MAXBITPOOLVALUEMIN KMaxBitpoolValues[KNumOfBitpoolValues-1]

const float KReconfigureLimitFactor = 0.02; // 2% of during KDataCollectDelay transferred data
const float KLimitCheckInterval = ((float)KDataCollectDelay/1000000.0); // Time (seconds) to collect packet drop data

// MODULE DATA STRUCTURES

// ================= MEMBER FUNCTIONS =======================

// -----------------------------------------------------------------------------
// CBTSACStreamerController::NewL
// Two-phased constructor.
// -----------------------------------------------------------------------------
//
CBTSACStreamerController* CBTSACStreamerController::NewL(MBTAudioAdaptationObserver& aObserver )
    {
    CBTSACStreamerController* self = new (ELeave) CBTSACStreamerController (aObserver);
    CleanupStack::PushL( self );
    self->ConstructL();
    CleanupStack::Pop( self );
    return self;
    }

    
// -----------------------------------------------------------------------------
// Destructor.
// -----------------------------------------------------------------------------
//
CBTSACStreamerController::~CBTSACStreamerController()
    {
    TRACE_FUNC
    Cancel();
    if(iAudioInput)
	    {
	    iAudioInput->Stop();
	    iAudioInput->Disconnect();
	    }
    delete iPacketDropIoctl;
    delete iEncoderCI;
    delete iBTStreamer;
    delete iAudioInput;
    iLib.Close();
	iTimer.Close(); 
	iBitpoolData.Close();
    TRACE_INFO((_L("CBTSACStreamerController::~CBTSACStreamerController() completed")))
    }

// -----------------------------------------------------------------------------
// CBTSACStreamerController::CBTSACStreamerController
// C++ default constructor.
// -----------------------------------------------------------------------------
//
CBTSACStreamerController::CBTSACStreamerController(MBTAudioAdaptationObserver& aObserver)
    : CActive( EPriorityNormal ), iObserver(aObserver)
    {
	CActiveScheduler::Add(this);
    }
    
// -----------------------------------------------------------------------------
// CBTSACStreamerController::ConstructL
// Symbian 2nd phase constructor.
// -----------------------------------------------------------------------------
//
void CBTSACStreamerController::ConstructL( )
    {
    TRACE_FUNC

	User::LeaveIfError(iTimer.CreateLocal()); 
	iThread = RThread();

	iBTStreamer = CBTAudioStreamer::NewL();

    LEAVE_IF_ERROR( iLib.Load( KBTAADLL ) );
    typedef TInt (*TOurLibraryFunction2)(MBTAudioStreamObserver&, MBTAudioErrorObserver&);
    TOurLibraryFunction2 newL2 = reinterpret_cast<TOurLibraryFunction2>(iLib.Lookup(1));
    iAudioInput = (CBTAudioStreamInputBase*)newL2(*iBTStreamer, *this);       

	TInt ret;
	ret = iAudioInput->Connect();
	if (ret) 
		{
		TRACE_INFO((_L("CBTSACStreamerController::ConstructL() Audio Input Connect Error %d"), ret))
		User::Leave(ret); 
		}

	ret = iAudioInput->SetFormat(KMMFFourCCCodeSBC);	
	if (ret)
   		{
 		TRACE_INFO((_L("CBTSACStreamerController::ConstructL() Audio Input SetFormat Error %d"), ret))
  		User::Leave(ret);
 		}

    iEncoderCI = reinterpret_cast<CSbcEncoderIntfc *> (iAudioInput->EncoderInterface(KUidSbcEncoderIntfc));
	User::LeaveIfNull(iEncoderCI);

	InitializeBitpoolDataL();
    iState = EStateIdle;
      
    TRACE_INFO((_L("CBTSACStreamerController::ConstructL() completed")))
    }
    
// -----------------------------------------------------------------------------
// CBTSACStreamerController::StartStream
// -----------------------------------------------------------------------------
//
TInt CBTSACStreamerController::StartStream(RSocket& aSocket, TInt aFrameLength )
	{
	TRACE_FUNC
	
	if (!(iBTStreamer) || !(iAudioInput) )    
		{
		return KErrNotFound;	
		}
    
    if (iState == EStateError)
    	{
    	iState = EStateIdle;
    	TInt err = iAudioInput->Connect();
		if (!err) 
			{
			err = iAudioInput->SetFormat(KMMFFourCCCodeSBC);
			}    	
		if (err)
	   		{
	   		TRACE_INFO((_L("CBTSACStreamerController::StartStream() Audio Input initialization Error %d"), err))
	  		return err;
	 		}
    	}
    
    if (iState == EStateIdle)    
    	{
	    TInt err = KErrNone;
	    TRAP( err, iBTStreamer->StartL(aSocket, aFrameLength, iAudioInput, iCurrentBitrate));

	    if ( err == KErrNone )
	    	{
	    	err = iAudioInput->Start(); 	
	    	}

		if ( err == KErrNone )
			{			
			TRACE_INFO((_L("CBTSACStreamerController::StartStream() Sending packet drop IOCTL")))
    		TRAP( err, iPacketDropIoctl = CActivePacketDropIoctl::NewL(*this, aSocket));
    		
    		if( err == KErrNone )
    			{
    			iPacketDropDeviation = 0;
				iTotalNbrOfDroppedPackets = 0;
    			iState = EStateStreaming;
				
				if(iCurrentBitpoolData->iMaxBitpoolValue < iMatchCap.MaxBitpoolValue())
					{
					TRACE_INFO((_L("CBTSACStreamerController::StartStream(), upgrade bitrate.")))
					// Streaming was stopped when the bitrate was lower than maximum, so upgrade it for starters.
					// iPacketDropIoctl->Start will be called after self completion.
					
					// Update current bitpool data to be highest possible. Highest possible bitpool value can be found from position 
					iCurrentBitpoolData = GetBitpoolData(0);
					if(iCurrentBitpoolData)
						{
						DoSelfComplete(EUpgradeBitrate, KErrNone);
						}
					else
						{
						err = KErrArgument;
						}
					}
				else if(iMatchCap.MaxBitpoolValue() > iBitpoolData[iBitpoolData.Count() - 1].iMaxBitpoolValue)
					{
					// Don't start receive packet drop events if max bitpool value is not bigger than min
					// bitpool value (we can't downgrade bitpool, we already have lowest possible value).
					DoSelfComplete(EStartStabilizingTimer, KErrNone);
					}
				TRACE_INFO((_L("CBTSACStreamerController::StartStream() completed")))
    			}
	    	}
	    if( err )
	    	{
	    	// In case someting went wrong stop both audio adaptation and streamer
	    	TRACE_INFO((_L("CBTSACStreamerController::StartStream() *Error: %d"), err))
	    	iAudioInput->Stop();
	    	iAudioInput->Disconnect();
	    	iBTStreamer->Stop();
      	
	    	//make sure iAudioInput->Connect() & SetFormat() get called in StartStream()
	    	iState = EStateError;
	    	}
	    return err;
    	}
    else
    	{
    	return KErrAlreadyExists;
    	}
	}
        
// -----------------------------------------------------------------------------
// CBTSACStreamerController::StopStream
// -----------------------------------------------------------------------------
//
TInt CBTSACStreamerController::StopStream()
	{
	TRACE_FUNC
    Cancel();
   	if (!(iBTStreamer) || !(iAudioInput))    
		{
		return KErrNotFound;	
		}
    else if (iState != EStateIdle )
    	{
      	iAudioInput->Stop();
      	iBTStreamer->Stop();
	   	delete iPacketDropIoctl; 
	   	iPacketDropIoctl = NULL; 
	   	iState = EStateIdle;    
	 	return KErrNone;	
    	}
    else
    	{
    	return KErrAlreadyExists; 
    	}
	}

// -----------------------------------------------------------------------------
// CBTSACStreamerController::ResetAudioInput
// -----------------------------------------------------------------------------
//
void CBTSACStreamerController::ResetAudioInput()
	{
	TRACE_FUNC
	iAudioInput->Stop();
	iAudioInput->Disconnect();
    TInt err = iAudioInput->Connect();
	if (!err) 
		{
		err = iAudioInput->SetFormat(KMMFFourCCCodeSBC);
		}    	
	if (err)
		{
		TRACE_INFO((_L("CBTSACStreamerController::ResetAudioInput() Audio Input initialization Error %d"), err))
		}	
	}

// -----------------------------------------------------------------------------
// CBTSACStreamerController::FillCapabilities
// -----------------------------------------------------------------------------
//	
TInt CBTSACStreamerController::FillCapabilities( TSBCCodecCapabilities& aSbc )
	{
	TRACE_FUNC

	TUint8 itemp = 0x00; 
    // Sampling Frequency
    TInt ret;
	RArray<TUint> SupportedSamplingFrequencies; 
	ret = iEncoderCI->GetSupportedSamplingFrequencies(SupportedSamplingFrequencies); 
	if ( !ret)
		{
		 itemp = 0x00; 
	
		 for (TInt i=0; i<SupportedSamplingFrequencies.Count(); i++ )
		 	{
			 if ( SupportedSamplingFrequencies[i] == TUint(16000) )
			 	{
				itemp = E16kHz;	// 	E16kHz		= 0x8 
				continue; 
			 	}
			 if ( SupportedSamplingFrequencies[i] == TUint(32000) )
			 	{
			 	itemp |= E32kHz; //	E32kHz		= 0x4
			 	continue; 
			 	}
			 if ( SupportedSamplingFrequencies[i] == TUint(44100) )
			 	{
			 	itemp |= E44100Hz;	// E44100Hz	= 0x2
			 	continue; 
				}
			 if ( SupportedSamplingFrequencies[i] == TUint(48000) )
			 	{
			 	itemp |= E48kHz;	// E48kHz	= 0x1
			 	continue; 
			 	}
		 	}
		 aSbc.SetSamplingFrequencies(itemp);
		 TRACE_INFO((_L("CBTSACStreamerController::FillCapabilities() Encoder Sampling Frequencies: %d"), itemp))
		}
	else
		{
		return ret; 
		}
	
	// Channel mode
    RArray<CSbcEncoderIntfc::TSbcChannelMode> SupportedChannelModes; 
    ret = iEncoderCI->GetSupportedChannelModes(SupportedChannelModes);
	if ( !ret )
		{
		 itemp = 0x00; 
	
		 for (TInt i=0; i<SupportedChannelModes.Count(); i++ )
		 	{
			 if ( SupportedChannelModes[i] ==  CSbcEncoderIntfc::ESbcChannelMono)
			 	{
				itemp = EMono;	// 	EMono			= 0x8	 		 		
				continue;		 		
			 	}
			 if ( SupportedChannelModes[i] == CSbcEncoderIntfc::ESbcChannelDual )
			 	{
		 		itemp |= EDualChannel;	// 	EDualChannel	= 0x4
			 	continue;
			 	}
			 if ( SupportedChannelModes[i] == CSbcEncoderIntfc::ESbcChannelStereo )
			 	{
				itemp |= EStereo;	// 	EStereo			= 0x2	 		
			 	continue;
				}
			 if ( SupportedChannelModes[i] == CSbcEncoderIntfc::ESbcChannelJointStereo )
			 	{
		 		itemp |= EJointStereo;	//	EJointStereo	= 0x1
			 	continue;
			 	}
		 	}
		 aSbc.SetChannelModes(itemp);
		 TRACE_INFO((_L("CBTSACStreamerController::FillCapabilities() Encoder Channel modes: %d"), itemp))
		}
	else
		{
		return ret; 
		}

    // Blocks
    RArray<TUint> SupportedNumOfBlocks; 
    ret = iEncoderCI->GetSupportedNumOfBlocks(SupportedNumOfBlocks); 
	if ( !ret )
		{
		 itemp = 0x00; 
	
		 for (TInt i=0; i<SupportedNumOfBlocks.Count(); i++ )
		 	{
			 if ( SupportedNumOfBlocks[i] ==  TUint(4))
			 	{
				itemp = EBlockLenFour;	//	 EBlockLenFour 		= 0x8		 		
				continue;		 		
			 	}
			 if ( SupportedNumOfBlocks[i] == TUint(8) )
			 	{
			 	itemp |= EBlockLenEight;	// 	EBlockLenEight 		= 0x4
			 	continue;
			 	}
			 if ( SupportedNumOfBlocks[i] == TUint(12) )
			 	{
			 	itemp |= EBlockLenTwelve;	// 	EBlockLenTwelve		= 0x2
			 	continue;
				}
			 if ( SupportedNumOfBlocks[i] == TUint(16) )
			 	{
			 	itemp |= EBlockLenSixteen;	// 	EBlockLenSixteen	= 0x1
			 	continue;
			 	}
		 	}
		 aSbc.SetBlockLengths(itemp);
		 TRACE_INFO((_L("CBTSACStreamerController::FillCapabilities() Encoder Blocks: %d"), itemp))
		}
	else
		{
		return ret; 
		}
		 
	// Subbands
	RArray<TUint> SupportedNumOfSubbands; 
	ret = iEncoderCI->GetSupportedNumOfSubbands(SupportedNumOfSubbands);
	if ( !ret )
		{
	    itemp = 0x0;
		for (TInt i=0; i<SupportedNumOfSubbands.Count(); i++ )
		 	{	
			 if ( SupportedNumOfSubbands[i] == TUint(4) )
			 	{
				itemp = EFourSubbands; // 	EFourSubbands  = 0x02
				continue; 
			 	}
			 if ( SupportedNumOfSubbands[i] == TUint(8) )
			 	{
			 	itemp |= EEightSubbands;	// 	EEightSubbands  = 0x01
			 	continue; 
			 	}
		 	}
		 aSbc.SetSubbands(itemp);
		 TRACE_INFO((_L("CBTSACStreamerController::FillCapabilities() Encoder SubBands: %d"), itemp))
		 }
	else
		{
		return ret; 
		}
		 
    // allocation method bitmask 
    RArray<CSbcEncoderIntfc::TSbcAllocationMethod> SupportedAllocationMethods;
    ret = iEncoderCI->GetSupportedAllocationMethods(SupportedAllocationMethods); 
	if ( !ret )
		{
	    itemp = 0x0;
		for (TInt i=0; i<SupportedAllocationMethods.Count(); i++ )
		 	{	
			 if ( SupportedAllocationMethods[i] == CSbcEncoderIntfc::ESbcAllocationSNR )
			 	{
				itemp = ESNR; // 	ESNR  = 0x02
				continue; 
			 	}
			 if ( SupportedAllocationMethods[i] == CSbcEncoderIntfc::ESbcAllocationLoudness )
			 	{
			 	itemp |= ELoudness;	// 	ELoudness  = 0x01
			 	continue; 
			 	}
		 	}
		 aSbc.SetAllocationMethods(itemp);
		 TRACE_INFO((_L("CBTSACStreamerController::FillCapabilities() Encoder Alloc method: %d"), itemp))
		 }
	else
		{
		return ret; 
		}
		 
	// bitpools
	TUint MinSupportedBitpoolSize; TUint MaxSupportedBitpoolSize; 
	ret = iEncoderCI->GetSupportedBitpoolRange(MinSupportedBitpoolSize, 
		                      				   MaxSupportedBitpoolSize);
	if ( !ret )
	 	{
		if (MaxSupportedBitpoolSize > MAXBITPOOLVALUEMAX)
	 	    {
	 	    MaxSupportedBitpoolSize = MAXBITPOOLVALUEMAX;
	 	    }
	 	// TUint8 to TInt
		aSbc.SetMaxBitpoolValue(MaxSupportedBitpoolSize);
		TRACE_INFO((_L("CBTSACStreamerController::FillCapabilities() Encoder Max bitpool: %d"), MaxSupportedBitpoolSize))
		aSbc.SetMinBitpoolValue(MinSupportedBitpoolSize);
		TRACE_INFO((_L("CBTSACStreamerController::FillCapabilities() Encoder Min bitpool: %d"), MinSupportedBitpoolSize))
	 	}
	else
		{
		return ret; 
		}	 
		 
    // save our local copy, 9 bytes on stack
    iLocalCap = aSbc;
	
	TRACE_INFO((_L("CBTSACStreamerController::FillCapabilities() Return: %d"), ret));	
	return ret;
	}
	
// -----------------------------------------------------------------------------
// CBTSACStreamerController::ConfigureSEP
// -----------------------------------------------------------------------------
//	
TInt CBTSACStreamerController::ConfigureSEP( TSBCCodecCapabilities& aDec )
	{
	TRACE_FUNC
	TInt err = KErrNone;
	TRAP(err, InitializeBitpoolDataL());
	if(err)
		return err;
	
	err = GetMatchingCaps(aDec);
	if(!err)
		{
		CheckAndAdjustBitpool(aDec);
		// Save the matching Caps
		iMatchCap = aDec;
		ReorganizeBitpoolTable(iMatchCap.MaxBitpoolValue());
		err = SetCurrentBitpoolData(iMatchCap.MaxBitpoolValue());
		if(!err)
			{
			iEncoderCI->SetBitpoolSize(iMatchCap.MaxBitpoolValue());
	  		// configure encoder
			err = iEncoderCI->ApplyConfig();
			}
		}
	TRACE_INFO((_L("CBTSACStreamerController::ConfigureSEP() return: %d"), err))
	return err;
	}

// -----------------------------------------------------------------------------
// CBTSACStreamerController::ConfigureSEPBitpool
// -----------------------------------------------------------------------------
//	
TInt CBTSACStreamerController::ConfigureSEPBitpool(EOngoingAction aAction)
	{
	TRACE_FUNC
    TInt err = KErrNone;
	TSBCCodecCapabilities newDecConfiguration; 
	memset(&newDecConfiguration, 0, sizeof(newDecConfiguration)); 
	newDecConfiguration = iMatchCap;
	TInt nextIndex = (aAction == EDowngradeBitrate) ? iCurrentBitpoolData->iDownBitpoolIndex : iCurrentBitpoolData->iUpBitpoolIndex;
	if(!IndexValid(nextIndex))
		{
		return KErrArgument;
		}
	TInt BitpoolValue = iBitpoolData[nextIndex].iMaxBitpoolValue;
	newDecConfiguration.SetMaxBitpoolValue(BitpoolValue);
	CheckAndAdjustBitpool(newDecConfiguration);
	
	TRACE_INFO((_L("CBTSACStreamerController::ConfigureSEPBitpool() Current FrameLength: %d"), iCurrentFrameLength))
	TRACE_INFO((_L("CBTSACStreamerController::ConfigureSEPBitpool() Current Bitrate: %d"), iCurrentBitrate))
	
	err = iBTStreamer->SetNewFrameLength(iCurrentFrameLength, iCurrentBitrate);
	if(!err)
		{
		TRACE_INFO((_L("CBTSACStreamerController::ConfigureSEPBitpool(), Reconfiguring the encoder...")))
		iEncoderCI->SetBitpoolSize(newDecConfiguration.MaxBitpoolValue());
		// configure encoder
		err = iEncoderCI->ApplyConfig();
		if(!err)
			{			
			err = SetCurrentBitpoolData(newDecConfiguration.MaxBitpoolValue());
			if(!err)
				{
				TRACE_INFO((_L("CBTSACStreamerController::ConfigureSEPBitpool(): Current BP: %d"), iCurrentBitpoolData->iMaxBitpoolValue))
				}			
			}
		TRACE_INFO((_L("CBTSACStreamerController::ConfigureSEPBitpool() The encoder reconfigured.")))
		}
	TRACE_INFO((_L("CBTSACStreamerController::ConfigureSEPBitpool() return: %d"), err))
	return err;
	}

// -----------------------------------------------------------------------------
// CBTSACStreamerController::FrameLength
// -----------------------------------------------------------------------------
//
TInt CBTSACStreamerController::FrameLength() const
	{
	TRACE_INFO((_L("CBTSACStreamerController::FrameLength() = %d"), iCurrentFrameLength))
	return iCurrentFrameLength;
	}

// -----------------------------------------------------------------------------
// CBTSACStreamerController::GetMatchingCaps
// -----------------------------------------------------------------------------
//
TInt CBTSACStreamerController::GetMatchingCaps(TSBCCodecCapabilities& aCaps)
	{
	TRACE_FUNC
	TInt ret = KErrNone; 
	TUint8 MatchingFreq, MatchingChnl, MatchingBlck, MatchingSub, MatchingAlloc;
	
	MatchingFreq = (iLocalCap.SamplingFrequencies() & aCaps.SamplingFrequencies());
	MatchingChnl = (iLocalCap.ChannelModes() & aCaps.ChannelModes()); 
	MatchingBlck = (iLocalCap.BlockLengths() & aCaps.BlockLengths());
	MatchingSub = (iLocalCap.Subbands() & aCaps.Subbands());
	MatchingAlloc = (iLocalCap.AllocationMethods() & aCaps.AllocationMethods());
	
	if ( 	 MatchingFreq  &&
			 MatchingChnl  &&
			 MatchingBlck 	&&
			 MatchingSub   &&
			 MatchingAlloc &&
		     ( iLocalCap.MinBitpoolValue() <= aCaps.MaxBitpoolValue() )  &&
			 ( iLocalCap.MaxBitpoolValue() >= aCaps.MinBitpoolValue() ) )
		{
		TRACE_INFO((_L("CBTSACStreamerController::GetMatchingCaps() accessory configuration suits us")))

		// Choose highest possible values that are supported
			
		// Sampling Frequency
		SetSamplingFrequency(aCaps, MatchingFreq);
		// Channel mode
		SetChannelMode(aCaps, MatchingChnl);
		// Blocks
		SetBlockLen(aCaps, MatchingBlck);			
		// Subbands			
		SetNumOfSubbands(aCaps, MatchingSub);	
		// Allocation method	
		SetAllocationMethod(aCaps, MatchingAlloc);		
		// Bitpool
		SetBitpoolValues(aCaps);
		}
	else // no match
		{
		TRACE_INFO((_L("CBTSACStreamerController::GetMatchingCaps() **No Matching Capabilities**")))
		ret = KErrNotFound; 
		}
	return ret;
	}

// -----------------------------------------------------------------------------
// CBTSACStreamerController::CheckAndAdjustBitpool
// -----------------------------------------------------------------------------
//
void CBTSACStreamerController::CheckAndAdjustBitpool(TSBCCodecCapabilities& aCap)
	{
  	TRACE_FUNC
	// ******* Adjust bitpool if necessary *****
	TInt targetbitrate; 
	TInt nChnls = GetNumOfChannels(aCap);
	TInt nSbands = GetNumOfSubbands(aCap);
	TInt nBlck  = GetBlockLen(aCap);
	TInt Freq = GetSamplingFrequency(aCap);
	TInt frameLength = FrameLengthFormula(aCap);
	// Note: this is the bitrate of the transmission. 
	TInt bitrateInt = 8 * frameLength * Freq / nSbands / nBlck; 
	
	TRACE_INFO((_L("CBTSACStreamerController::CheckAndAdjustBitpool(), nChnls = %d"), nChnls))
	TRACE_INFO((_L("CBTSACStreamerController::CheckAndAdjustBitpool(), nSbands = %d"), nSbands))
	TRACE_INFO((_L("CBTSACStreamerController::CheckAndAdjustBitpool(), nBlck = %d"), nBlck))
	TRACE_INFO((_L("CBTSACStreamerController::CheckAndAdjustBitpool(), Freq = %d"), Freq))
	TRACE_INFO((_L("CBTSACStreamerController::CheckAndAdjustBitpool(), MaxBP = %d"), aCap.MaxBitpoolValue()))
	TRACE_INFO((_L("CBTSACStreamerController::CheckAndAdjustBitpool(), Frame length = %d"), frameLength))
	TRACE_INFO((_L("CBTSACStreamerController::CheckAndAdjustBitpool(), Bitrate = %d"), bitrateInt))

	// max bit rate:	320kb/s for mono, 
	//					512kb/s for two-channel modes
	if (aCap.ChannelModes() & EMono)
		{
		if (bitrateInt <= 320000.0)		
			{
			targetbitrate = bitrateInt;
		 	}
		 else // target bitrate=320kbps
		 	{
		 	TRACE_INFO((_L("CBTSACStreamerController::CheckAndAdjustBitpool() Adjusting...")))
		 	targetbitrate = 320000.0; 
		 	TInt BP = ( ((targetbitrate*nSbands*nBlck)/Freq) - 32 - (4*nSbands*nChnls) ) / (nBlck*nChnls); 
		 	aCap.SetMaxBitpoolValue(BP);
		 	}
		 }
	else
		 {
		 if (bitrateInt <= 512000.0)
		 	{
			targetbitrate = bitrateInt; 
		 	}
		else // target bitrate=512kbps
			{
			TRACE_INFO((_L("CBTSACStreamerController::CheckAndAdjustBitpool() Adjusting...")))
			targetbitrate = 512000.0; 
			TInt BP = 0;
			if (aCap.ChannelModes() & EDualChannel)
		 		{
		 	  	BP = ( ((targetbitrate*nSbands*nBlck)/Freq) - 32 - (4*nSbands*nChnls) ) / (nBlck*nChnls); 	
	 	  		}
			else
				{
				TInt join = (aCap.ChannelModes() & EJointStereo) ? 1 : 0; 
		 	  	BP = ( ((targetbitrate*nSbands*nBlck)/Freq) - 32 - (4*nSbands*nChnls) -  (nSbands*join) ) / (nBlck);
				}
				
			aCap.SetMaxBitpoolValue(BP);
			// Calculate new frame length
			frameLength = FrameLengthFormula(aCap);
		 	}	
		}

	iCurrentFrameLength = frameLength;
	iCurrentBitrate = targetbitrate; 	
	TRACE_INFO((_L("CBTSACStreamerController::CheckAndAdjustBitpool(), After Adjustment MaxBP: %d"), aCap.MaxBitpoolValue()))
	TRACE_INFO((_L("CBTSACStreamerController::CheckAndAdjustBitpool(), After Adjustment Frame length: %d"), iCurrentFrameLength))
  	TRACE_INFO((_L("CBTSACStreamerController::CheckAndAdjustBitpool(), After Adjustment Bitrate: %d"), iCurrentBitrate))
	}

// -----------------------------------------------------------------------------
// CBTSACStreamerController::RunL
// -----------------------------------------------------------------------------
//
void CBTSACStreamerController::RunL()
	{
	TRACE_FUNC
	switch(iStatus.Int())
		{
   		case KErrNone:
      		{
			switch( iOngoingAction )
				{
				case EErrorSending:
					{
					TRACE_INFO((_L("CBTSACStreamerController::RunL(), ErrorSending")))
					
					TRACE_INFO((_L("CBTSACStreamerController::RunL(), TotalNbrOfDroppedPackets: %d"), iTotalNbrOfDroppedPackets))
					TInt TotalNbrOfDroppedBits = iTotalNbrOfDroppedPackets*8;
					TRACE_INFO((_L("CBTSACStreamerController::RunL(), Total dropped bits: %d"), TotalNbrOfDroppedBits))
					TRACE_INFO((_L("CBTSACStreamerController::RunL(), Current Bitrate: %d"), iCurrentBitrate))
					TInt ReconfigureLimit = KLimitCheckInterval*iCurrentBitrate*KReconfigureLimitFactor;
					TRACE_INFO((_L("CBTSACStreamerController::RunL(), Limit for reconfigure : %d bits"), ReconfigureLimit))
					TRACE_INFO((_L("CBTSACStreamerController::RunL(), PacketDropDeviation: %d (limit %d)"), iPacketDropDeviation, iCurrentBitpoolData->iMaxDeviation))
					
					if((TotalNbrOfDroppedBits > ReconfigureLimit) && (iPacketDropDeviation >= iCurrentBitpoolData->iMaxDeviation))
						{
						iPacketDropIoctl->Cancel();
						
						if(iCurrentBitpoolData->iMinimumMaxBitpool)
							{
							TRACE_INFO((_L("CBTSACStreamerController::RunL(), Minimum max bitpool reached.")))
							TRACE_INFO((_L("CBTSACStreamerController::RunL(), Stop receive packet drops.")))
							return;
							}												
						
						// Initialize values for upgrade timer. Only if setting min bitpool value fails, start retry timer.
						TInt delay = KStabilizationDelay;
						iOngoingAction = EStabilize;
						TInt err = ConfigureSEPBitpool(EDowngradeBitrate);							
						if(err)
							{
							iOngoingAction = EDowngradeBitrate;
							delay = KRetryTimerDelay;
							}

		    			iTimer.After(iStatus, delay);
		    			SetActive();
						}
					
					iPacketDropDeviation = 0;
					iTotalNbrOfDroppedPackets = 0;
					break;
					}					
				
				case EStabilize:
					// Start receive overflow indications again
					TRACE_INFO((_L("CBTSACStreamerController::RunL(), stabilize timer expired.")))
					iPacketDropIoctl->Start();
					break;

				case EDowngradeBitrate:
				case EUpgradeBitrate:
				case EStartStabilizingTimer:
					{
					TRACE_INFO((_L("CBTSACStreamerController::RunL(), Action = %d"), iOngoingAction))
					TInt err = KErrNone;
					TInt delay = KStabilizationDelay;
					if(iOngoingAction != EStartStabilizingTimer)
						{
						err = ConfigureSEPBitpool(iOngoingAction);
						}
					if(err)
						{
						delay = KRetryTimerDelay;
						}
					else
						{
	    				TRACE_INFO((_L("CBTSACStreamerController::RunL(), stabilize timer started")))
	    				iOngoingAction = EStabilize;
						}

    				iTimer.After(iStatus, delay);
    				SetActive();
					break;
					}				
				}
        	break;
      		}
      	
		case KErrGeneral: // We have received error from audio adaptation
			{
			TRACE_INFO((_L("CBTSACStreamerController::RunL(), KErrGeneral")))
			iAudioInput->Stop();
			iAudioInput->Disconnect();
			iObserver.NotifyError(KErrGeneral);
			break;
			}
			
   		default:
   			TRACE_INFO((_L("CBTSACStreamerController::RunL(), #default")))
      		break;
   		}  
    TRACE_INFO((_L("CBTSACStreamerController::RunL() completed")))
	}

// -----------------------------------------------------------------------------
// CBTSACStreamerController::DoCancel
// -----------------------------------------------------------------------------
//
void CBTSACStreamerController::DoCancel()
	{
	TRACE_FUNC
    iTimer.Cancel();
    TRACE_INFO((_L("CBTSACStreamerController::DoCancel() completed")))
	}

// -----------------------------------------------------------------------------
// CBTSACStreamerController::RunError
// -----------------------------------------------------------------------------
//
TInt CBTSACStreamerController::RunError(TInt /*aError*/)    
	{
	TRACE_FUNC
	return 0;
	}
    
// -----------------------------------------------------------------------------
// CBTSACStreamerController::Error
// -----------------------------------------------------------------------------
//
TInt CBTSACStreamerController::Error(const TInt aError) 
	{
	TRACE_INFO((_L("CBTSACStreamerController::Error() %d"), aError))
	TInt ret = KErrNone;
	switch(aError)
		{
		case KErrOverflow:
		case KErrUnderflow:
			{
			DoSelfComplete(EErrorSending, KErrNone);
			break;
			}
		case KErrGeneral:
			{
			if(iState != EStateError)
				{
				iState = EStateError;
				DoSelfComplete(iOngoingAction, KErrGeneral);
				}
			break;
			}
		default:
			{
			ret = KErrUnknown;
			break;
			}
		}
	return ret;
	}

// -----------------------------------------------------------------------------
// CBTSACStreamerController::GetCaps
// -----------------------------------------------------------------------------
//
TSBCCodecCapabilities& CBTSACStreamerController::GetCaps()
	{
	return iLocalCap;
	}

// -----------------------------------------------------------------------------
// CBTSACStreamerController::SetBlockLen
// -----------------------------------------------------------------------------
//
void CBTSACStreamerController::SetBlockLen(TSBCCodecCapabilities& aCap, TUint8 aBlockLen)
	{
	// Set Block Lenght, select highest one
	if ( aBlockLen & EBlockLenSixteen )
		{
		iEncoderCI->SetNumOfBlocks(TUint(16));
		aCap.SetBlockLengths(EBlockLenSixteen);
		TRACE_INFO((_L("CBTSACStreamerController::SetBlockLen(), BlockLength: EBlockLenSixteen")))
		}
	else if ( aBlockLen & EBlockLenTwelve )
		{
		iEncoderCI->SetNumOfBlocks(TUint(12));
		aCap.SetBlockLengths(EBlockLenTwelve);	
		TRACE_INFO((_L("CBTSACStreamerController::SetBlockLen(), BlockLength: EBlockLenTwelve")))
		}
	else if ( aBlockLen & EBlockLenEight )
		{
		iEncoderCI->SetNumOfBlocks(TUint(8));
		aCap.SetBlockLengths(EBlockLenEight);
		TRACE_INFO((_L("CBTSACStreamerController::SetBlockLen(), BlockLength: EBlockLenEight")))
		}
	else if ( aBlockLen & EBlockLenFour )
		{
		iEncoderCI->SetNumOfBlocks(TUint(4));
		aCap.SetBlockLengths(EBlockLenFour);
		TRACE_INFO((_L("CBTSACStreamerController::SetBlockLen(), BlockLength: EBlockLenFour")))
		}
	else
		{
		TRACE_INFO((_L("CBTSACStreamerController::SetBlockLen(), No matching Block Length")))
		}
	}
	
// -----------------------------------------------------------------------------
// CBTSACStreamerController::GetBlockLen
// -----------------------------------------------------------------------------
//
TInt CBTSACStreamerController::GetBlockLen(TSBCCodecCapabilities& aCap) const
	{
	TInt nBlck  = 0;
	switch( aCap.BlockLengths() )
		{
		case EBlockLenSixteen:
			nBlck = 16;
			break;
		case EBlockLenTwelve:
			nBlck = 12;
			break;
		case EBlockLenEight:
			nBlck = 8;
			break;
		case EBlockLenFour:
			nBlck = 4;
			break;
		default:
			TRACE_INFO((_L("CBTSACStreamerController::GetBlockLen(), #default")))
			nBlck = 16;
			break;
		}
	return nBlck;
	}

// -----------------------------------------------------------------------------
// CBTSACStreamerController::SetBitpoolValues
// -----------------------------------------------------------------------------
//
void CBTSACStreamerController::SetBitpoolValues(TSBCCodecCapabilities& aCap)
	{
	// Define max bitpool
	TInt MaxBP = 0;
	TInt minBitpool = aCap.MinBitpoolValue();
	TInt maxBitpool = aCap.MaxBitpoolValue();	
	TBool ProperMaxBitpoolFound = EFalse;
	
	if( minBitpool == maxBitpool )
	    {
        // Remote supports only one bitpool value
        iRemoteSupportsOnlyOneValue = ETrue;
        TRACE_INFO((_L("CBTSACStreamerController::SetBitpoolValues(), remote supports only one bitpool value")))
        TRACE_INFO((_L("CBTSACStreamerController::SetBitpoolValues(), Max Bitpool: %d"), maxBitpool))
        TRACE_INFO((_L("CBTSACStreamerController::SetBitpoolValues(), Min Bitpool: %d"), minBitpool))
        return;
	    }
	
	for(TInt i = 0 ; i < KNumOfBitpoolValues ; i++)
		{
		if(maxBitpool >= KMaxBitpoolValues[i])
			{
			MaxBP = KMaxBitpoolValues[i];
			ProperMaxBitpoolFound = ETrue;
			break;
			}
		}
	if(!ProperMaxBitpoolFound)
		{
		// None of our proposed max bitpool values weren't suitable for accessory.
		// Let's use the one which was proposed by the accessory.
		MaxBP = maxBitpool;
		}
	
	// Define min bitpool. This bitpool value is negotiated with sink.
	TInt MinBP = (iLocalCap.MinBitpoolValue() < minBitpool) ? minBitpool : iLocalCap.MinBitpoolValue();
	
	// Define bitpool which is used for medium quality streaming (when streaming is interfered for some reason).
	// This is real lowest bitpool value which is used for streaming.
	
	// Check if selected max bitpool value is smaller than our default min bitpool value, if it is, set
	// minimum max bitpool value to be same as max value otherwise just update it with our default min value.
	if(MaxBP < MAXBITPOOLVALUEMIN)
		{
		// Update the minumum bitpool data
		iBitpoolData[iBitpoolData.Count()-1].iMaxBitpoolValue = MaxBP;
		}
	else if(MAXBITPOOLVALUEMIN < MinBP) // Check also that minimum max bitpool value is not smaller than bitpool which is negotiated for the link.
		{
		iBitpoolData[iBitpoolData.Count()-1].iMaxBitpoolValue = MinBP;
		}
	
	TRACE_INFO((_L("CBTSACStreamerController::SetBitpoolValues(), Remote Max Bitpool: %d"), maxBitpool))
	TRACE_INFO((_L("CBTSACStreamerController::SetBitpoolValues(), Remote Min Bitpool: %d"), minBitpool))
	
	aCap.SetMaxBitpoolValue(MaxBP);
	TRACE_INFO((_L("CBTSACStreamerController::SetBitpoolValues(), Max Bitpool: %d"), MaxBP))
	aCap.SetMinBitpoolValue(MinBP);
	TRACE_INFO((_L("CBTSACStreamerController::SetBitpoolValues(), Min Bitpool: %d"), MinBP))
	}

// -----------------------------------------------------------------------------
// CBTSACStreamerController::SetAllocationMethod
// -----------------------------------------------------------------------------
//
void CBTSACStreamerController::SetAllocationMethod(TSBCCodecCapabilities& aCap, TUint8 aAllocationMethod)
	{
	// Set Allocation Method, select highest one
	if ( aAllocationMethod & ELoudness )
		{
		iEncoderCI->SetAllocationMethod(CSbcEncoderIntfc::ESbcAllocationLoudness);
		aCap.SetAllocationMethods(ELoudness);
		TRACE_INFO((_L("CBTSACStreamerController::SetAllocationMethod(), AllocationMethod: ELoudness")))
		}
	else if ( aAllocationMethod & ESNR )
		{
		iEncoderCI->SetAllocationMethod(CSbcEncoderIntfc::ESbcAllocationSNR);
		aCap.SetAllocationMethods(ESNR);
		TRACE_INFO((_L("CBTSACStreamerController::SetAllocationMethod(), AllocationMethod: ESNR")))
		}
	else
		{
		TRACE_INFO((_L("CBTSACStreamerController::SetAllocationMethod(), No matching Allocation Method")))
		}
	}
// -----------------------------------------------------------------------------
// CBTSACStreamerController::SetChannelMode
// -----------------------------------------------------------------------------
//
void CBTSACStreamerController::SetChannelMode(TSBCCodecCapabilities& aCap, TUint8 aChannelMode)
	{
	// Set Channel mode, select highest one
	if ( aChannelMode & EJointStereo )
		{
		iEncoderCI->SetChannelMode(CSbcEncoderIntfc::ESbcChannelJointStereo);
		aCap.SetChannelModes(EJointStereo);
		TRACE_INFO((_L("CBTSACStreamerController::SetChannelMode(), ChannelMode: EJointStereo")))
		}
	else if ( aChannelMode & EStereo )
		{
		iEncoderCI->SetChannelMode(CSbcEncoderIntfc::ESbcChannelStereo);
		aCap.SetChannelModes(EStereo);	
		TRACE_INFO((_L("CBTSACStreamerController::SetChannelMode(), ChannelMode: EStereo")))
		}
	else if ( aChannelMode & EDualChannel )
		{
		iEncoderCI->SetChannelMode(CSbcEncoderIntfc::ESbcChannelDual);
		aCap.SetChannelModes(EDualChannel);
		TRACE_INFO((_L("CBTSACStreamerController::SetChannelMode(), ChannelMode: EDualChannel")))
		}
	else if ( aChannelMode & EMono )
		{
		iEncoderCI->SetChannelMode(CSbcEncoderIntfc::ESbcChannelMono);
		aCap.SetChannelModes(EMono);
		TRACE_INFO((_L("CBTSACStreamerController::SetChannelMode(), ChannelMode: EMono")))
		}
	else
		{
		TRACE_INFO((_L("CBTSACStreamerController::SetChannelMode(), No matching Channel Mode")))
		}
	}

// -----------------------------------------------------------------------------
// CBTSACStreamerController::SetSamplingFrequency
// -----------------------------------------------------------------------------
//
void CBTSACStreamerController::SetSamplingFrequency(TSBCCodecCapabilities& aCap, TUint8 aFrequency)
	{
	// Set Sampling Frequency, select highest one
	if ( aFrequency & E48kHz )
		{
		iEncoderCI->SetSamplingFrequency(TUint(48000));
		aCap.SetSamplingFrequencies(E48kHz);
		TRACE_INFO((_L("CBTSACStreamerController::SetSamplingFrequency(), Sampling Frequency: E48kHz")))
		}
	else if ( aFrequency & E44100Hz )
		{
		iEncoderCI->SetSamplingFrequency(TUint(44100));
		aCap.SetSamplingFrequencies(E44100Hz);
		TRACE_INFO((_L("CBTSACStreamerController::SetSamplingFrequency(), Sampling Frequency: E44100Hz")))
		}
	else if ( aFrequency & E32kHz )
		{
		iEncoderCI->SetSamplingFrequency(TUint(32000));
		aCap.SetSamplingFrequencies(E32kHz);
		TRACE_INFO((_L("CBTSACStreamerController::SetSamplingFrequency(), Sampling Frequency: E32kHz")))
		}
	else if ( aFrequency & E16kHz )
		{
		iEncoderCI->SetSamplingFrequency(TUint(16000));
		aCap.SetSamplingFrequencies(E16kHz);
		TRACE_INFO((_L("CBTSACStreamerController::SetSamplingFrequency(), Sampling Frequency: E16kHz")))
		}
	else
		{
		TRACE_INFO((_L("CBTSACStreamerController::SetSamplingFrequency(), No matching Sampling Frequency")))
		}
	}

// -----------------------------------------------------------------------------
// CBTSACStreamerController::GetSamplingFrequency
// -----------------------------------------------------------------------------
//
TInt CBTSACStreamerController::GetSamplingFrequency(TSBCCodecCapabilities& aCap) const
	{
	TInt Freq  = 0;
	switch( aCap.SamplingFrequencies() )
		{
		case E48kHz:
			Freq = 48000;
			break;
		case E44100Hz:
			Freq = 44100;
			break;
		case E32kHz:
			Freq = 32000;
			break;
		case E16kHz:
			Freq = 16000;
			break;
		default:
			TRACE_INFO((_L("CBTSACStreamerController::GetSamplingFrequency(), #default")))
			Freq = 48000;
			break;
		}
	return Freq;
	}

// -----------------------------------------------------------------------------
// CBTSACStreamerController::GetNumOfChannels
// -----------------------------------------------------------------------------
//
TInt CBTSACStreamerController::GetNumOfChannels(TSBCCodecCapabilities& aCap) const
	{
	TInt nChnls = (aCap.ChannelModes() & EMono) ? 1 : 2;
	return nChnls;
	}

// -----------------------------------------------------------------------------
// CBTSACStreamerController::SetNumOfSubbands
// -----------------------------------------------------------------------------
//
void CBTSACStreamerController::SetNumOfSubbands(TSBCCodecCapabilities& aCap, TUint8 aNumOfSubbands)
	{	
	// Set Number of Subbands, select highest one
	if ( aNumOfSubbands & EEightSubbands )
		{
		iEncoderCI->SetNumOfSubbands(TUint(8));
		aCap.SetSubbands(EEightSubbands);
		TRACE_INFO((_L("CBTSACStreamerController::SetNumOfSubbands(), Subband: EEightSubbands")))
		}
	else if ( aNumOfSubbands & EFourSubbands )
		{
		iEncoderCI->SetNumOfSubbands(TUint(4));
		aCap.SetSubbands(EFourSubbands);
		TRACE_INFO((_L("CBTSACStreamerController::SetNumOfSubbands(), Subband: EFourSubbands")))
		}
	else
		{
		TRACE_INFO((_L("CBTSACStreamerController::SetNumOfSubbands(), No matching Subband")))
		}
	}

// -----------------------------------------------------------------------------
// CBTSACStreamerController::GetNumOfSubbands
// -----------------------------------------------------------------------------
//
TInt CBTSACStreamerController::GetNumOfSubbands(TSBCCodecCapabilities& aCap) const
	{
	TInt nSbands = (aCap.Subbands() & EEightSubbands) ? 8 : 4;
	return nSbands;
	}

// -----------------------------------------------------------------------------
// CBTSACStreamerController::FrameLengthFormula
// -----------------------------------------------------------------------------
//
TInt CBTSACStreamerController::FrameLengthFormula(TSBCCodecCapabilities& aCap) const
	{
	TInt join = ( aCap.ChannelModes() & EJointStereo ) ? 1 : 0; 
	TInt nChnls = GetNumOfChannels(aCap);
	TInt nSbands = GetNumOfSubbands(aCap);
	TInt nBlck  = GetBlockLen(aCap);
	
	// For mono (and dual channel) mode the formula is slightly differend than for stereo mode(s). 
	TInt frameLength = 
		( (aCap.ChannelModes() & EMono) || (aCap.ChannelModes() & EDualChannel) ) ? 
		  4 + ((4 * nSbands * nChnls) / 8) + ( (nBlck * nChnls * aCap.MaxBitpoolValue()) / 8): 
		  4 + ((4 * nSbands * nChnls) / 8) + ( (join * nSbands + nBlck * aCap.MaxBitpoolValue()) / 8)/* + join*/; 

	// Note:	last "+ join" in latter version of the formula is for joint stereo. 
	//			Otherwise the formula doesn't calculate the extra byte that's in the header.
	return frameLength;
	}

// -----------------------------------------------------------------------------
// CBTSACStreamerController::PacketsDropped
// -----------------------------------------------------------------------------
//
void CBTSACStreamerController::PacketsDropped(TInt aError)
	{
	TRACE_FUNC
	if(!iTotalNbrOfDroppedPackets)
		{
		// This is first packet drop indication after previous sample interval
		iFirstPacketDropTime.UniversalTime();
		}
	TTime timeNow;
	timeNow.UniversalTime();
    iPacketDropDeviation = static_cast<TInt32>(timeNow.MicroSecondsFrom(iFirstPacketDropTime).Int64());
	
	iTotalNbrOfDroppedPackets += aError;
	
	if(!IsActive())
		{
		iOngoingAction = EErrorSending;
		iTimer.After(iStatus, KDataCollectDelay);
		SetActive();
		}
	}

// -----------------------------------------------------------------------------
// CBTSACStreamerController::SetCurrentBitpoolData
// -----------------------------------------------------------------------------
//
TInt CBTSACStreamerController::SetCurrentBitpoolData(TInt aBitpool)
	{
	TRACE_FUNC
	TInt err = KErrNone;
	TInt Index = GetIndex(aBitpool);
	if(Index >= 0)
		{
		iCurrentBitpoolData = GetBitpoolData(Index);
		}
	else
		{
		err = KErrNotFound;
		}
	return err;
	}
// -----------------------------------------------------------------------------
// CBTSACStreamerController::GetIndex
// -----------------------------------------------------------------------------
//
TInt CBTSACStreamerController::GetIndex(TInt aBitpool)
	{
	TInt Bitpool = aBitpool;
	if(aBitpool > iMatchCap.MaxBitpoolValue())
		{
		Bitpool = iMatchCap.MaxBitpoolValue();
		}
	for(TInt i = 0 ; i < iBitpoolData.Count() ; i++)
		{
		if(Bitpool == iBitpoolData[i].iMaxBitpoolValue)
			{
			return i;
			}
		}
	return KErrNotFound;
	}

// -----------------------------------------------------------------------------
// CBTSACStreamerController::IndexValid
// -----------------------------------------------------------------------------
//
TBool CBTSACStreamerController::IndexValid(TInt aIndex)
	{
	if(aIndex >= 0 && aIndex < iBitpoolData.Count())
		return ETrue;
	else
		return EFalse;
	}

// -----------------------------------------------------------------------------
// CBTSACStreamerController::InitializeBitpoolData
// -----------------------------------------------------------------------------
//
void CBTSACStreamerController::InitializeBitpoolDataL()
	{
	TRACE_FUNC
	iRemoteSupportsOnlyOneValue = EFalse;
	TBitpoolData data;
	iBitpoolData.Reset();
	for(TInt i = 0 ; i < KNumOfBitpoolValues ; i++)
		{
		data.iMaxBitpoolValue = KMaxBitpoolValues[i];
		data.iMaxDeviation = KDeviationValues[i];
		data.iUpBitpoolIndex = (i == 0) ? i : i - 1;
		data.iIndex = i;
		data.iDownBitpoolIndex = (i == KNumOfBitpoolValues - 1) ? i : i + 1;
		data.iMinimumMaxBitpool = (i == KNumOfBitpoolValues - 1) ? ETrue : EFalse;
		iBitpoolData.AppendL(data);
		}
	}

// -----------------------------------------------------------------------------
// CBTSACStreamerController::GetBitpoolData
// -----------------------------------------------------------------------------
//
TBitpoolData* CBTSACStreamerController::GetBitpoolData(TInt aIndex)
	{
	if(aIndex < 0 || aIndex >= iBitpoolData.Count())
		return NULL;
	
	return &iBitpoolData[aIndex];
	}

// -----------------------------------------------------------------------------
// CBTSACStreamerController::ReorganizeBitpoolTable
// -----------------------------------------------------------------------------
//
void CBTSACStreamerController::ReorganizeBitpoolTable(TInt aNegotiatedMaxBitpool)
    {
    TRACE_INFO((_L("CBTSACStreamerController::ReorganizeBitpoolTable(), Negotiated Max Bitpool %d"), aNegotiatedMaxBitpool))
            
    TInt tablesToBeRemoved;
    if( iRemoteSupportsOnlyOneValue )
        {
        // Remote supports only one bitpool value, so we need only one table, remove rest. 
        tablesToBeRemoved = KNumOfBitpoolValues - 1;
        }
    else
        {
        // Find proper bitpool value, start checking from the lowest possible bitpool value
        for(tablesToBeRemoved = (KNumOfBitpoolValues - 1) ; tablesToBeRemoved > 0 ; tablesToBeRemoved--)
            {
            if(aNegotiatedMaxBitpool <= KMaxBitpoolValues[tablesToBeRemoved])
                {            
                break;
                }
            }
        }
    if( tablesToBeRemoved >= iBitpoolData.Count() )
        {
        // This should never happen.
        TRACE_INFO((_L("CBTSACStreamerController::ReorganizeBitpoolTable(), Index error!")))
        tablesToBeRemoved = 0;
        TRAPD(err, InitializeBitpoolDataL())
        if(err)
            {
            return;
            }
        }
    
    // Remove tables we don't need
    TInt idx;
    for( idx = 0 ; idx < tablesToBeRemoved ; idx++)
        {
        iBitpoolData.Remove(0);             
        }    
    TRACE_INFO((_L("CBTSACStreamerController::ReorganizeBitpoolTable(), Tables removed: %d"), tablesToBeRemoved))
    
    if( tablesToBeRemoved )
        {
        for( idx = 0 ; idx < iBitpoolData.Count() ; idx++)
            {
            if( idx == 0 )
                {
                // Index zero has the highest matching/negotiated bitpool value, update it.
                // Rest values remains to be according to default table.
                iBitpoolData[idx].iMaxBitpoolValue = aNegotiatedMaxBitpool;
                }
            // Update indexing.
            iBitpoolData[idx].iIndex = idx;
            iBitpoolData[idx].iUpBitpoolIndex = (idx == 0) ? idx : idx - 1;
            iBitpoolData[idx].iDownBitpoolIndex = (idx == iBitpoolData.Count() - 1) ? idx : idx + 1;
            iBitpoolData[idx].iMinimumMaxBitpool = (idx == iBitpoolData.Count() - 1) ? ETrue : EFalse;
            }
        }
    
    TRACE_INFO((_L("CBTSACStreamerController::ReorganizeBitpoolTable(), Tables left: %d"), iBitpoolData.Count()))
    for( idx = 0 ; idx < iBitpoolData.Count() ; idx++)
        {
        TRACE_INFO((_L("CBTSACStreamerController::ReorganizeBitpoolTable(), Table[%d] MaxBP: %d"), idx, iBitpoolData[idx].iMaxBitpoolValue))
        }
    }

// -----------------------------------------------------------------------------
// CBTSACStreamerController::DoSelfComplete
// -----------------------------------------------------------------------------
//
void CBTSACStreamerController::DoSelfComplete(EOngoingAction aAction, TInt aError)
	{
	TRACE_FUNC
	if (IsActive())
    	{
    	// Stop timer
    	Cancel();
    	}
    if (!IsActive())
    	{
		// Just self complete here, handle error in RunL
		iOngoingAction = aAction;
		TRequestStatus *status = &iStatus;
		iStatus = KRequestPending;
 		iThread.RequestComplete(status, aError);
 		SetActive();
    	}
    else
    	{
    	TRACE_INFO((_L("CBTSACStreamerController::DoSelfComplete((), Couldn't do self complete")))
    	}
	}
//  End of File      
