// Copyright (c) 2006-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:
//
#include "cdevaudiocontrol.h"
#include <a3f/audioprocessingunittypeuids.h>
#include <mmf/server/mmfswcodecwrappercustominterfacesuids.hrh>
#include <a3f/maudiocontext.h>
#include <a3f/maudiostream.h>
#include <a3f/maudiocodec.h>
#include <a3f/maudiogaincontrol.h>
const TInt KMicroSecondsInSecond = 1000000;
const TInt KDefaultBufferSize = 4096;
const TUint KMaxCallbacksExpected = 2;
const TUint KDefaultSampleRate = 8000;
const TUid KDefaultMode = {KA3FModeMonoValue};
class TSampleRateTableEntry
{
public:
TInt iSampleRateValue;
TMMFSampleRate iSampleRate;
};
const TSampleRateTableEntry KRateTableLookup[] = {
{ 8000, EMMFSampleRate8000Hz },
{ 11025, EMMFSampleRate11025Hz },
{ 12000, EMMFSampleRate12000Hz },
{ 16000, EMMFSampleRate16000Hz },
{ 22050, EMMFSampleRate22050Hz },
{ 24000, EMMFSampleRate24000Hz },
{ 32000, EMMFSampleRate32000Hz },
{ 44100, EMMFSampleRate44100Hz },
{ 48000, EMMFSampleRate48000Hz },
{ 64000, EMMFSampleRate64000Hz },
{ 88200, EMMFSampleRate88200Hz },
{ 96000, EMMFSampleRate96000Hz },
};
const TInt KMaxSampleRateIndex = 11; // must agree with length of table
class TAudioModeTableEntry
{
public:
TMMFMonoStereo iAudioModeValue;
TUid iAudioMode;
};
const TAudioModeTableEntry KModeTableLookup[] = {
{ EMMFMono, {KA3FModeMonoValue} },
{ EMMFStereo, {KA3FModeStereoNonInterleavedValue} },
};
const TInt KMaxModeIndex = 1; // must agree with length of table
// ---------------------------------------------------------------------------
// Default constructor
// ---------------------------------------------------------------------------
//
CDevAudioControl::CDevAudioControl()
{
TRACE_CREATE();
DP_CONTEXT(CDevAudioControl::CDevAudioControl *CD1*, CtxDevSound, DPLOCAL);
DP_IN();
// Local cache default values
iCurrentSampleRate = KDefaultSampleRate;
iCurrentMode = KDefaultMode;
iOutstandingCallbacks = KMaxCallbacksExpected; //by default we expect 2 callbacks for capabilities.
iCallbackFromAdaptor = KCallbackNone;
DP_OUT();
}
void CDevAudioControl::ConstructL(CDevAudio* aDevAudio, MDevSoundAdaptationObserver& aDevSoundObserver)
{
TRACE_CREATE();
DP_CONTEXT(CDevAudioControl::ConstructL *CD1*, CtxDevSound, DPLOCAL);
DP_IN();
iDevAudio = aDevAudio;
iAdaptationObserver = &aDevSoundObserver;
iObserverRegistered = EFalse;
TAudioChannelGain left;
TAudioChannelGain right;
left.iLocation = TAudioChannelGain::ELeft;
right.iLocation = TAudioChannelGain::ERight;
User::LeaveIfError(iChannelGains.Append(left)); // assumed element 0 in rest of code
User::LeaveIfError(iChannelGains.Append(right)); // assumed element 1 in rest of code
// Note this could be delayed now (volume is internal to adaptor until later in cycle)
// Needed to allow CMMFDevSound::MaxVolume and similar calls before CMMFDevSound::InitializeL
TAny* interface(NULL);
interface = iDevAudio->iGainControl->Interface(KUidAudioGainControl);
iGainControl = static_cast<MAudioGainControl*>(interface);
DP_OUT();
}
// ---------------------------------------------------------------------------
// Destructor
// ---------------------------------------------------------------------------
//
CDevAudioControl::~CDevAudioControl()
{
DP_CONTEXT(CDevAudioControl::~CDevAudioControl *CD1*, CtxDevSound, DPLOCAL);
DP_IN();
iChannelGains.Close();
iSupportedRates.Close();
iSupportedModes.Close();
DP_OUT();
}
// -----------------------------------------------------------------------------
// CacheAudioCodecIf
//
TInt CDevAudioControl::CacheAudioCodecIf()
{
DP_CONTEXT(CDevAudioControl::CacheAudioCodecIf *CD1*, CtxDevSound, DPLOCAL);
DP_IN();
if (iDevAudio->iAudioCodec==NULL)
{
DP0_RET(KErrNotReady,"%d");
}
TInt err = KErrNone;
if (iAudioCodecIf==NULL)
{
MAudioCodec* codecInterface = static_cast<MAudioCodec*>(iDevAudio->iAudioCodec->Interface(KUidAudioCodec));
__ASSERT_ALWAYS (codecInterface, CDevAudioControl::Panic(EAudioCodecIsNull));
iAudioCodecIf = codecInterface;
}
DP0_RET(err,"%d");
}
// -----------------------------------------------------------------------------
// CDevAudioControl::Initialize
// -----------------------------------------------------------------------------
//
TInt CDevAudioControl::Initialize(TUid /*aFormat*/)
{
DP_CONTEXT(CDevAudioControl::Initialize *CD1*, CtxDevSound, DPLOCAL);
DP_IN();
ASSERT(EFalse);
iObserverRegistered = EFalse;
DP0_RET(KErrNone,"%d");
}
// -----------------------------------------------------------------------------
// CDevAudioControl::Uninitialize
// -----------------------------------------------------------------------------
//
TInt CDevAudioControl::Uninitialize()
{
DP_CONTEXT(CDevAudioControl::Uninitialize *CD1*, CtxDevSound, DPLOCAL);
DP_IN();
// Remove pUnits only allowed when stream is uninitialized
TInt err = iDevAudio->iAudioStream->Uninitialize();
if (err == KErrNone)
{
iDevAudio->iActiveState = EDevSoundAdaptorUninitialising;
err = iDevAudio->iAudioContext->Commit();
}
DP0_RET(err,"%d");
}
// -----------------------------------------------------------------------------
// CDevAudioControl::Unload
// -----------------------------------------------------------------------------
//
TInt CDevAudioControl::Unload()
{
DP_CONTEXT(CDevAudioControl::Unload *CD1*, CtxDevSound, DPLOCAL);
DP_IN();
TInt err = iDevAudio->iAudioStream->Unload();
if (err == KErrNone)
{
err = iDevAudio->iAudioContext->Commit();
}
if (err == KErrNone)
{
iDevAudio->iActiveState = EDevSoundAdaptorUnloading;
}
DP0_RET(err,"%d");
}
// -----------------------------------------------------------------------------
// CDevAudioControl::GetCapabilities
// -----------------------------------------------------------------------------
//
TInt CDevAudioControl::GetCapabilities(TMMFCapabilities& aCap)
{
DP_CONTEXT(CDevAudioControl::GetCapabilities *CD1*, CtxDevSound, DPLOCAL);
DP_IN();
// At this phase of CAP, we only care about current codec capabilities.
// This will be supported as soon as the A3F API changes to support this are ready
TInt err = KErrNone;
if (iDevAudio->iActiveState != EDevSoundAdaptorCreated_Uninitialised)
{
err = CacheAudioCodecIf();
if (err != KErrNone)
{
DP0_RET(err, "%d");
}
if (err == KErrNone)
{
err = iAudioCodecIf->GetSupportedModes(iSupportedModes);
if (err == KErrNone)
{
aCap.iChannels = GetModes(iSupportedModes);
err = iAudioCodecIf->GetSupportedSamplesRates(iSupportedRates);
if (err == KErrNone)
{
aCap.iRate = GetSampleRates(iSupportedRates);
}
else
{
//If was a problem getting sampleRates we donīt expect callbacks and return
iOutstandingCallbacks = 0;
}
}
else
{
//If was a problem getting modes we donīt expect callbacks and return
iOutstandingCallbacks = 0;
}
}
}
else
{
err = KErrNotReady;
}
DP0_RET(err, "%d");
}
// -----------------------------------------------------------------------------
// CDevAudioControl::GetConfig
// -----------------------------------------------------------------------------
//
TInt CDevAudioControl::GetConfig(TMMFCapabilities& aConfig)
{
DP_CONTEXT(CDevAudioControl::GetConfig *CD1*, CtxDevSound, DPLOCAL);
DP_IN();
TInt err(KErrNone);
//TODO add a return error code if the sample rate or the channels are not found
//We need to transform the local values to a supported value for the client
aConfig.iRate = static_cast<TMMFSampleRate>(GetSampleRate(iCurrentSampleRate));
aConfig.iChannels = static_cast<TMMFMonoStereo>(GetMode(iCurrentMode));
aConfig.iBufferSize = KDefaultBufferSize;
DP2(DLINFO, "rate 0x%x, channels 0x%x", aConfig.iRate, aConfig.iChannels);
DP0_RET(err, "%d");
}
// -----------------------------------------------------------------------------
// CDevAudioControl::SetConfig
// -----------------------------------------------------------------------------
//
TInt CDevAudioControl::SetConfig(const TMMFCapabilities& aConfig)
{
DP_CONTEXT(CDevAudioControl::SetConfig *CD1*, CtxDevSound, DPLOCAL);
DP_IN();
// TODO need to ensure if iChannels or iSampleRate is outside known values, then
// the code handles that gracefully and returns the appropriate error code
TInt err(KErrNone);
TUid mode = KNullUid;
//Reset the desired values
iDesiredSampleRate = 0;
iDesiredMode = KNullUid;
err = ResolveMode(aConfig.iChannels, mode);
if (err != KErrNone)
{
DP0_RET(err, "%d");
}
err = ResolveSampleRate(aConfig.iRate, iDesiredSampleRate);
if (err != KErrNone)
{
DP0_RET(err, "%d");
}
// At this phase of CAP, we only care about codec, which checks config against
// its own capabilities. Verification against stream specific capabilities
// should be added later on.
err = CacheAudioCodecIf();
if (err != KErrNone)
{
DP0_RET(err, "%d");
}
err = iAudioCodecIf->SetSampleRate(iDesiredSampleRate);
if(err == KErrNone)
{
err = iAudioCodecIf->SetMode(mode);
}
if(err == KErrNone)
{
err = iDevAudio->iAudioContext->Commit();
if (err == KErrNone)
{
iDesiredMode = mode;
}
}
DP0_RET(err, "%d");
}
// -----------------------------------------------------------------------------
// CDevAudioControl::ProcessInit
// -----------------------------------------------------------------------------
//
TInt CDevAudioControl::ProcessInit()
{
DP_CONTEXT(CDevAudioControl::ProcessInit *CD1*, CtxDevSound, DPLOCAL);
DP_IN();
ASSERT(EFalse);
DP0_RET(KErrNone,"%d");
}
// -----------------------------------------------------------------------------
// CDevAudioControl::ProcessData
// -----------------------------------------------------------------------------
//
void CDevAudioControl::ProcessData()
{
DP_CONTEXT(CDevAudioControl::ProcessData *CD1*, CtxDevSound, DPLOCAL);
DP_IN();
ASSERT(EFalse);
DP_OUT();
}
// -----------------------------------------------------------------------------
// CDevAudioControl::GetSamples
// -----------------------------------------------------------------------------
//
TInt CDevAudioControl::GetSamples()
{
DP_CONTEXT(CDevAudioControl::GetSamples *CD1*, CtxDevSound, DPLOCAL);
DP_IN();
TInt err(KErrNone);
TInt samplesplayed(0);
TTimeIntervalMicroSeconds timeProcessed(0);
err = iDevAudio->iAudioStream->GetStreamTime(timeProcessed);
DP1(DLINFO,"CDevAudioControl::GetSamples iCurrentSampleRate %d",iCurrentSampleRate);
if(err == KErrNone)
{
samplesplayed = (timeProcessed.Int64() * iCurrentSampleRate + KMicroSecondsInSecond/2) / TInt64(KMicroSecondsInSecond);
}
//TODO manage the error
DP0_RET(samplesplayed, "%d");
}
// -----------------------------------------------------------------------------
// CDevAudioControl::Stop
// -----------------------------------------------------------------------------
//
TInt CDevAudioControl::Stop()
{
DP_CONTEXT(CDevAudioControl::Stop *CD1*, CtxDevSound, DPLOCAL);
DP_IN();
ASSERT(EFalse);
DP0_RET(KErrNone, "%d");
}
// -----------------------------------------------------------------------------
// CDevAudioControl::Pause
// -----------------------------------------------------------------------------
//
TInt CDevAudioControl::Pause()
{
DP_CONTEXT(CDevAudioControl::Pause *CD1*, CtxDevSound, DPLOCAL);
DP_IN();
ASSERT(EFalse);
DP0_RET(KErrNone, "%d");
}
// -----------------------------------------------------------------------------
// CDevAudioControl::CustomInterface
// -----------------------------------------------------------------------------
//
TAny* CDevAudioControl::CustomInterface(TUid aInterfaceId)
{
DP_CONTEXT(CDevAudioControl::CustomInterface *CD1*, CtxDevSound, DPLOCAL);
DP_IN();
TAny* ciPtr(NULL);
TInt err = KErrNone;
if(iDevAudio->iAudioStream)
{
TAny* ptr = iDevAudio->iAudioStream->Interface(KUidExtensionInferface);
if(ptr)
{
MCustomInterfaceSupport* ciSupport = static_cast<MCustomInterfaceSupport*>(ptr);
if(!iObserverRegistered)
{
err = ciSupport->RegisterObserver(*this);
if(err == KErrNone)
{
iObserverRegistered = ETrue;
}
}
err = ciSupport->RequestCustomInterface(aInterfaceId, ciPtr);
if( err != KErrNone)
{
ciPtr = NULL;
}
}
}
DP0_RET(ciPtr, "0x%x");
}
// -----------------------------------------------------------------------------
// CDevAudioControl::SetGain
// -----------------------------------------------------------------------------
TInt CDevAudioControl::SetGains(TInt aDevSoundGain, TInt aDevSoundMaxGain, TInt aBalance[2], const TTimeIntervalMicroSeconds& aRampDuration, TBool aBecomingActive)
{
DP_CONTEXT(CDevAudioControl::SetGains *CD1*, CtxDevSound, DPLOCAL);
DP_IN();
ASSERT(aDevSoundGain>=0 && aDevSoundGain<=aDevSoundMaxGain); // higher layer assumed to scale
ASSERT(aBalance[ELeftCh]>=0 && aBalance[ELeftCh]<=100);
ASSERT(aBalance[ERightCh]>=0 && aBalance[ERightCh]<=100);
ASSERT(aDevSoundMaxGain>0); // assumed max gain is positive
TInt a3fMaxGain;
TInt err = iGainControl->GetMaxGain(a3fMaxGain);
if (err==KErrNone)
{
iLegacyGain = TInt(TReal(aDevSoundGain)*TReal(a3fMaxGain)/TReal(aDevSoundMaxGain)+0.5);
ASSERT(iLegacyGain>=0 && iLegacyGain<=a3fMaxGain);
iLegacyLeft = aBalance[ELeftCh];
iLegacyRight = aBalance[ERightCh];
MapGains();
// VolumeRamp is only applied when DevSound is becoming active
if(err == KErrNone)
{
if (aRampDuration > 0 && aBecomingActive)
{
err = iGainControl->SetGain(iChannelGains, KUidGainSawTooth, aRampDuration);
}
else
{
err = iGainControl->SetGain(iChannelGains);
}
}
// This call will result on commit only when we are already active
// otherwise the changes will be commited by the DevAudioControl
// It means we're here due to RequestGainAndBalance call
if(err == KErrNone && !aBecomingActive)
{
err = iDevAudio->iAudioContext->Commit();
}
}
DP0_RET(err,"%d");
}
// -----------------------------------------------------------------------------
// CDevAudioControl::MapAndSetGains
// -----------------------------------------------------------------------------
//
void CDevAudioControl::MapGains()
{
DP_CONTEXT(CDevAudioControl::MapGains *CD1*, CtxDevSound, DPLOCAL);
DP_IN();
// Map legacy values to CAP channel array.
if ( iLegacyLeft == iLegacyRight )
{
iChannelGains[ELeftCh].iGain = iLegacyGain;
iChannelGains[ERightCh].iGain = iLegacyGain;
}
else if ( iLegacyLeft > iLegacyRight )
{
iChannelGains[ELeftCh].iGain = iLegacyGain;
iChannelGains[ERightCh].iGain =
static_cast<TUint>((iLegacyGain*iLegacyRight)/iLegacyLeft);
}
else
{
iChannelGains[ERightCh].iGain = iLegacyGain;
iChannelGains[ELeftCh].iGain =
static_cast<TUint>((iLegacyGain*iLegacyLeft)/iLegacyRight);
}
DP_OUT();
}
// -----------------------------------------------------------------------------
// CDevAudioControl::DestroyChain
// -----------------------------------------------------------------------------
//
TBool CDevAudioControl::DestroyChain()
{
DP_CONTEXT(CDevAudioControl::DestroyChain *CD1*, CtxDevSound, DPLOCAL);
DP_IN();
TInt err = KErrNone;
TBool readyToDestroy = EFalse;
switch(iDevAudio->iActiveState)
{
case EDevSoundAdaptorActive_Active:
case EDevSoundAdaptorPaused_Primed:
{
err = iDevAudio->iAudioStream->Stop();
if(err == KErrNone)
{
err = iDevAudio->iAudioContext->Commit();
}
if (err == KErrNone)
{
iDevAudio->iActiveState = EDevSoundAdaptorStopping;
}
}
break;
case EDevSoundAdaptorInitialised_Idle:
{
err = iDevAudio->iAudioStream->Unload();
if(err == KErrNone)
{
err = iDevAudio->iAudioContext->Commit();
}
if (err == KErrNone)
{
iDevAudio->iActiveState = EDevSoundAdaptorUnloading;
}
}
break;
case EDevSoundAdaptorInitialised_Initialised:
{
err = iDevAudio->iAudioStream->Uninitialize();
if(err == KErrNone)
{
err = iDevAudio->iAudioContext->Commit();
}
if (err == KErrNone)
{
iDevAudio->iActiveState = EDevSoundAdaptorUninitialising;
}
}
break;
case EDevSoundAdaptorCreated_Uninitialised:
readyToDestroy = ETrue;
default:
break;
}
// Destroy sequence fail!
if(err != KErrNone)
{
DP0(DLINFO, "================ Destroy sequence fail! ================");
readyToDestroy = ETrue;
}
// Set the flag only when needed
iDevAudio->iClosing = !readyToDestroy;
DP0_RET(readyToDestroy,"%d");
}
// -----------------------------------------------------------------------------
// CDevAudioControl::RemoveProcessingUnits
// -----------------------------------------------------------------------------
//
TInt CDevAudioControl::RemoveProcessingUnits()
{
DP_CONTEXT(CDevAudioControl::RemoveProcessingUnits *CD1*, CtxDevSound, DPLOCAL);
DP_IN();
// Remove pUnits only allowed when stream is uninitialized
TInt err = iDevAudio->iAudioStream->RemoveProcessingUnit(iDevAudio->iAudioSource);
if(err == KErrNone)
{
err = iDevAudio->iAudioStream->RemoveProcessingUnit(iDevAudio->iAudioSink);
}
if(err == KErrNone)
{
err = iDevAudio->iAudioStream->RemoveProcessingUnit(iDevAudio->iAudioCodec);
}
if (err == KErrNone)
{
err = iDevAudio->iAudioContext->Commit();
}
if(err == KErrNone)
{
iDevAudio->iActiveState = EDevSoundAdaptorRemovingProcessingUnits;
}
DP0_RET(err,"%d");
}
// -----------------------------------------------------------------------------
// From class MAudioStreamObserver
// CDevAudioControl::StateEvent
// -----------------------------------------------------------------------------
//
void CDevAudioControl::StateEvent(MAudioStream& /*aStream*/,
TInt /*aReason*/,
TAudioState /*aNewState*/)
{
DP_CONTEXT(CDevAudio::StateEvent *CD1*, CtxDevSound, DPLOCAL);
DP_IN();
ASSERT(EFalse);
DP_OUT();
}
// -----------------------------------------------------------------------------
// From class MAudioStreamObserver
// CDevAudioControl::AddProcessingUnitComplete
// -----------------------------------------------------------------------------
//
void CDevAudioControl::AddProcessingUnitComplete(MAudioStream& /*aStream*/,
MAudioProcessingUnit* /*aInstance*/,
TInt /*aError*/)
{
}
// -----------------------------------------------------------------------------
// From class MAudioStreamObserver
// CDevAudioControl::RemoveProcessingUnitComplete
// -----------------------------------------------------------------------------
//
void CDevAudioControl::RemoveProcessingUnitComplete(MAudioStream& /*aStream*/,
MAudioProcessingUnit* /*aInstance*/,
TInt /*aError*/)
{
}
// -----------------------------------------------------------------------------
// From class MAudioStreamObserver
// CDevAudioControl::ProcessingFinished
// -----------------------------------------------------------------------------
//
void CDevAudioControl::ProcessingFinished(MAudioStream& /*aStream*/)
{
}
// -----------------------------------------------------------------------------
// From class MAudioStreamObserver
// CDevAudioControl::FlushComplete
// -----------------------------------------------------------------------------
//
void CDevAudioControl::FlushComplete (MAudioStream& /*aStream*/, TInt aError)
{
// no action needed - should complete as part of the ContextEvent.
// otherwise could callback.
TInt err = KErrNone;
if(iPauseResumeSequenceDueToEmptyBuffers)
{
// Flush operation failed
if(aError != KErrNone)
{
iPauseResumeSequenceDueToEmptyBuffers = EFalse;
iAdaptationObserver->CallbackFromAdaptorReceived(KCallbackFlushComplete, aError);
}
// Handle throw-off scenarios, resume is not possible from here
// 1. ProcessingFinished has occurred
// 2. Preemption occurred
else if(iCallbackFromAdaptor != KCallbackNone ||
iDevAudio->iActiveState != EDevSoundAdaptorPaused_Primed)
{
iPauseResumeSequenceDueToEmptyBuffers = EFalse;
iAdaptationObserver->CallbackFromAdaptorReceived(KCallbackFlushComplete, KErrNone);
}
else
{
err = Resume();
if(err != KErrNone)
{
iPauseResumeSequenceDueToEmptyBuffers = EFalse;
iAdaptationObserver->CallbackFromAdaptorReceived(KCallbackFlushComplete, aError);
}
// Once ContextEvent be received
// EmptyBuffers can be considered completed
}
}
// EmptyBuffers operation has concluded here
// we didn't go through pause - resume sequence
else
{
iAdaptationObserver->CallbackFromAdaptorReceived(KCallbackFlushComplete, aError);
}
}
// -----------------------------------------------------------------------------
// From class MAudioGainControlObserver
// CDevAudioControl::MaxRampTimeChanged
// -----------------------------------------------------------------------------
//
void CDevAudioControl::MaxRampTimeChanged(MAudioGainControl& /*aGain*/)
{
DP_CONTEXT(CDevAudioControl::MaxRampTimeChanged *CD1*, CtxDevSound, DPLOCAL);
DP_IN();
// this is not cached, no actions needed
DP_OUT();
}
// -----------------------------------------------------------------------------
// From class MAudioGainControlObserver
// CDevAudioControl::MaxGainChanged
// -----------------------------------------------------------------------------
//
void CDevAudioControl::MaxGainChanged(MAudioGainControl& /*aGain*/)
{
DP_CONTEXT(CDevAudioControl::MaxGainChanged *CD1*, CtxDevSound, DPLOCAL);
DP_IN();
// this is not cached, no actions needed
DP_OUT();
}
// -----------------------------------------------------------------------------
// From class MAudioGainControlObserver
// CDevAudioControl::GainChanged
// -----------------------------------------------------------------------------
//
void CDevAudioControl::GainChanged(MAudioGainControl& aGain, TInt aError)
{
DP_CONTEXT(CDevAudioControl::GainChanged *CD1*, CtxDevSound, DPLOCAL);
DP1_IN("aError=%d", aError);
if(aError != KErrNone)
{
// Either our request failed, or MMRC has forced some values, and we
// have to update local values.
aGain.GetGain(iChannelGains);
ASSERT(iChannelGains.Count()==2);
// Map CAP channel array to legacy values.
// assumption: left%+right%=100
if ( iChannelGains[ELeftCh].iGain == iChannelGains[ERightCh].iGain )
{
iLegacyGain = iChannelGains[ELeftCh].iGain;
iLegacyLeft = 50;
iLegacyRight = 50;
}
else if ( iChannelGains[ELeftCh].iGain > iChannelGains[ERightCh].iGain )
{
iLegacyGain = iChannelGains[ELeftCh].iGain;
iLegacyLeft = static_cast<TUint>
((100*iLegacyGain)/(iLegacyGain+iChannelGains[ERightCh].iGain));
iLegacyRight = 100 - iLegacyLeft;
//(not that accurate, but sufficient for now)
}
else
{
iLegacyGain = iChannelGains[ERightCh].iGain;
iLegacyRight = static_cast<TUint>
((100*iLegacyGain)/(iLegacyGain+iChannelGains[ELeftCh].iGain));
iLegacyLeft = 100 - iLegacyRight;
}
DP3(DLINFO,"New values :iLegacyGain %d, iLegacyLeft %d, iLegacyRight %d",
iLegacyGain,iLegacyLeft,iLegacyRight);
}
else
{
// our request completed succesfully, no need to update cached values
// just print values in debug version
#ifdef _DEBUG
RArray<TAudioChannelGain> gains;
TUint left;
TUint right;
TUint gain;
aGain.GetGain(gains);
ASSERT(gains.Count()==2);
if ( iChannelGains[ELeftCh].iGain == iChannelGains[ERightCh].iGain )
{
gain = iChannelGains[ELeftCh].iGain;
left = 50;
right = 50;
}
else if ( iChannelGains[ELeftCh].iGain > iChannelGains[ERightCh].iGain )
{
gain = iChannelGains[ELeftCh].iGain;
left =
static_cast<TUint>((100*gain)/(gain+iChannelGains[ERightCh].iGain));
right = 100 - left;
}
else
{
gain = iChannelGains[ERightCh].iGain;
right =
static_cast<TUint>((100*gain)/(gain+iChannelGains[ELeftCh].iGain));
left = 100 - right;
}
gains.Close();
DP3(DLINFO,"KErrNone (gain %d, left %d, right %d)", gain,left,right);
#endif
}
DP_OUT();
}
// -----------------------------------------------------------------------------
// From class MAudioCodecObserver
// CDevAudioControl::SampleRateSet
// -----------------------------------------------------------------------------
void CDevAudioControl::SampleRateSet(TInt aError)
{
if(aError==KErrNone)
{
//Review if we call SetConfig or is only the first time that we load the codec
if (iDesiredSampleRate > 0)
{
iCurrentSampleRate = iDesiredSampleRate;
}
iDesiredSampleRate = 0;
}
}
// -----------------------------------------------------------------------------
// From class MAudioCodecObserver
// CDevAudioControl::ModeSet
// -----------------------------------------------------------------------------
void CDevAudioControl::ModeSet(TInt aError)
{
if(aError==KErrNone)
{
//Review if we call SetConfig or is only the first time that we load the codec
if (iDesiredMode != KNullUid)
{
iCurrentMode = iDesiredMode;
}
iDesiredMode = KNullUid;
}
}
// -----------------------------------------------------------------------------
// From class MAudioCodecObserver
// CDevAudioControl::GetSupportedSampleRatesComplete
// -----------------------------------------------------------------------------
void CDevAudioControl::GetSupportedSampleRatesComplete(TInt aError)
{
iSupportedRates.Reset();
CompleteMessageCap(aError);
}
// -----------------------------------------------------------------------------
// From class MAudioCodecObserver
// CDevAudioControl::GetSupportedModesComplete
// -----------------------------------------------------------------------------
void CDevAudioControl::GetSupportedModesComplete(TInt aError)
{
iSupportedModes.Reset();
CompleteMessageCap(aError);
}
// -----------------------------------------------------------------------------
// CDevAudioControl::CompleteMessageCap
// -----------------------------------------------------------------------------
void CDevAudioControl::CompleteMessageCap(TInt aError)
{
if (iOutstandingCallbacks > 1) //waiting until the 2 outstanding callbacks arrival.
{
iOutstandingCallbacks--;
iError = aError; //keeping the error.
}
else
{
if (iError == KErrNone)
{
iAdaptationObserver->AsynchronousOperationComplete(aError, ETrue);
}
else
{
iAdaptationObserver->AsynchronousOperationComplete(iError, ETrue);
}
iError = KErrNone;
iOutstandingCallbacks = KMaxCallbacksExpected;
}
}
// -----------------------------------------------------------------------------
// CDevAudioControl::SetToneData
// -----------------------------------------------------------------------------
//
TInt CDevAudioControl::SetToneData(TToneData& /*aToneData*/)
{
DP_CONTEXT(CDevAudioControl::SetToneData *CD1*, CtxDevSound, DPLOCAL);
DP_IN();
DP0_RET(KErrNotSupported, "%d");
}
// -----------------------------------------------------------------------------
// From class MAudioContextObserver
// CDevAudio::ContextEvent
// -----------------------------------------------------------------------------
//
void CDevAudioControl::ContextEvent(TUid aEvent, TInt aError)
{
DP_CONTEXT(CDevAudioControl::ContextEvent *CD1*, CtxDevSound, DPLOCAL);
DP_IN();
if (aEvent == KUidA3FContextUpdateComplete)
{
if(iIgnoreAsyncOpComplete)
{
iAdaptationObserver->PreemptionFinishedCallbackReceived(ETrue);
iIgnoreAsyncOpComplete = EFalse;
}
else
{
iAdaptationObserver->AsynchronousOperationComplete(aError, ETrue);
}
}
else if(aEvent == KUidA3FContextPreEmption || aEvent == KUidA3FContextPreEmptedCommit)
{
//Preemption during the below states should complete invoke AsynOperationComplete
if(iDevAudio->iActiveState!=EDevSoundAdaptorActivating && iDevAudio->iActiveState!=EDevSoundAdaptorLoading &&
iDevAudio->iActiveState!=EDevSoundAdaptorStopping && iDevAudio->iActiveState!=EDevSoundAdaptorUnloading
&& iDevAudio->iActiveState!=EDevSoundAdaptorPausing)
{
iIgnoreAsyncOpComplete = ETrue;
iAdaptationObserver->PreemptionStartedCallbackReceived();
}
}
DP_OUT();
}
// -----------------------------------------------------------------------------
// From class MCustomInterfaceSupportObserver
// CDevAudio::CustomInterfaceRemoval
// -----------------------------------------------------------------------------
//
void CDevAudioControl::CustomInterfaceRemoval(TUid aUid, TAny* /*aPtr*/)
{
DP_CONTEXT(CDevAudioControl::CustomInterfaceRemoval *CD1*, CtxDevSound, DPLOCAL);
DP_IN();
// TODO: Review this functionality
iAdaptationObserver->InterfaceDeleted(aUid);
DP_OUT();
}
// ---------------------------------------------------------------------------
// CDevAudioControl::ResolveSampleRate
// ---------------------------------------------------------------------------
TInt CDevAudioControl::ResolveSampleRate(TInt aSampleRate, TInt& aSampleRateValue)
{
DP_CONTEXT(CDevAudioControl::ResolveSampleRate, CtxDevSound, DPLOCAL);
DP_IN();
TInt err(KErrArgument);
for (TUint i=0; i<=KMaxSampleRateIndex; i++)
{
if(KRateTableLookup[i].iSampleRate == aSampleRate)
{
aSampleRateValue = KRateTableLookup[i].iSampleRateValue;
err = KErrNone;
break;
}
}
//To avoid the value return a non desired value.
if (err != KErrNone)
{
aSampleRateValue = 0;
}
DP0_RET(err, "%d");
}
// ---------------------------------------------------------------------------
// CDevAudioControl::ResolveMode
// ---------------------------------------------------------------------------
TInt CDevAudioControl::ResolveMode(TUint aModeValue, TUid& aMode)
{
DP_CONTEXT(CDevAudioControl::ResolveMode *CD1*, CtxDevSound, DPLOCAL);
DP_IN();
TInt err(KErrArgument);
for (TInt i=0; i<=KMaxModeIndex; i++)
{
const TAudioModeTableEntry& entry = KModeTableLookup[i];
if (entry.iAudioModeValue == aModeValue)
{
aMode = entry.iAudioMode;
err = KErrNone;
break;
}
}
DP0_RET(err,"%d");
}
// ---------------------------------------------------------------------------
// CDevAudioControl::GetModes
// ---------------------------------------------------------------------------
TUint CDevAudioControl::GetModes(const RArray<TUid>& aMode)
{
DP_CONTEXT(CDevAudioControl::GetModes *CD1*, CtxDevSound, DPLOCAL);
DP_IN();
TUint result = 0;
TInt count = aMode.Count();
for (TInt i=0; i<count; i++)
{
result |= GetMode(aMode[i]);
}
DP0_RET(result,"%d");
}
// ---------------------------------------------------------------------------
// CDevAudioControl::GetMode
// ---------------------------------------------------------------------------
TUint CDevAudioControl::GetMode(TUid aMode)
{
DP_CONTEXT(CDevAudioControl::GetMode *CD1*, CtxDevSound, DPLOCAL);
DP_IN();
TUint result = 0;
for (TInt e=0; e<=KMaxModeIndex; e++)
{
if(KModeTableLookup[e].iAudioMode == aMode)
{
result = KModeTableLookup[e].iAudioModeValue;
break;
}
}
DP0_RET(result,"%d");
}
// ---------------------------------------------------------------------------
// CDevAudioControl::GetSampleRates
// ---------------------------------------------------------------------------
TUint CDevAudioControl::GetSampleRates(const RArray<TInt>& aSampleRates)
{
DP_CONTEXT(CDevAudioControl::GetSampleRates *CD1*, CtxDevSound, DPLOCAL);
DP_IN();
TUint result = 0;
TInt count = aSampleRates.Count();
for (TInt i=0; i<count; i++)
{
result |= GetSampleRate(aSampleRates[i]);
}
DP0_RET(result,"%d");
}
// ---------------------------------------------------------------------------
// CDevAudioControl::GetSampleRate
// ---------------------------------------------------------------------------
TUint CDevAudioControl::GetSampleRate(TInt aSampleRates)
{
DP_CONTEXT(CDevAudioControl::GetSampleRate *CD1*, CtxDevSound, DPLOCAL);
DP_IN();
TUint result = 0;
TInt position = 0;
TInt lowerbound = 0;
TInt upperbound = KMaxSampleRateIndex;
if ((aSampleRates < KRateTableLookup[lowerbound].iSampleRateValue) || (aSampleRates > KRateTableLookup[upperbound].iSampleRateValue))
{
//value request not found in the array.
DP0_RET(result,"%d");
}
//Binary Search
position = ( lowerbound + upperbound) / 2;
while((KRateTableLookup[position].iSampleRateValue != aSampleRates) && (lowerbound <= upperbound))
{
if (KRateTableLookup[position].iSampleRateValue > aSampleRates)
{
upperbound = position - 1;
}
else
{
lowerbound = position + 1;
}
position = (lowerbound + upperbound) / 2;
}
result = KRateTableLookup[position].iSampleRate;
DP0_RET(result,"%d");
}
// ---------------------------------------------------------------------------
// CDevAudioControl::ProcessingFinishedReceived
// ---------------------------------------------------------------------------
TInt CDevAudioControl::ProcessingFinishedReceived(TBool& /*aAyncOperation*/)
{
return KErrNone;
}
// ---------------------------------------------------------------------------
// CDevAudioControl::ProcessingError
// ---------------------------------------------------------------------------
TInt CDevAudioControl::ProcessingError(TBool& /*aAyncOperation*/)
{
return KErrNone;
}
// ---------------------------------------------------------------------------
// CDevAudioControl::RequestEmptyBuffers
// ---------------------------------------------------------------------------
TInt CDevAudioControl::RequestEmptyBuffers()
{
DP_CONTEXT(CDevAudioControl::RequestEmptyBuffers *CD1*, CtxDevSound, DPLOCAL);
DP_IN();
TInt err(KErrNotReady);
if(iDevAudio)
{
if(iDevAudio->iActiveState == EDevSoundAdaptorPaused_Primed)
{
err = iDevAudio->iAudioStream->Flush();
}
else if (iDevAudio->iActiveState == EDevSoundAdaptorActive_Active)
{
err = Pause();
if(err == KErrNone)
{
iPauseResumeSequenceDueToEmptyBuffers = ETrue;
}
}
}
DP0_RET(err,"%d");
};
void CDevAudioControl::Panic(TDevSoundAdaptorPanicCode aCode)
{
_LIT(KMMFDevSoundAdaptorPanicCategory, "DevSoundAdaptor");
User::Panic(KMMFDevSoundAdaptorPanicCategory, aCode);
}
// ---------------------------------------------------------------------------
// CDevAudioControl::GetTimePlayed
// ---------------------------------------------------------------------------
TInt CDevAudioControl::GetTimePlayed(TTimeIntervalMicroSeconds& aTime)
{
DP_CONTEXT(CDevAudioControl::GetTimePlayed *CD1*, CtxDevSound, DPLOCAL);
DP_IN();
TInt err = iDevAudio->iAudioStream->GetStreamTime(aTime);
DP0_RET(err,"%d");
}
// ---------------------------------------------------------------------------
// CDevAudioControl::Resume
// ---------------------------------------------------------------------------
TBool CDevAudioControl::Resume()
{
DP_CONTEXT(CDevAudioControl::Stop *CD1*, CtxDevSound, DPLOCAL);
DP_IN();
ASSERT(EFalse);
DP0_RET(KErrNone, "%d");
}
// -----------------------------------------------------------------------------
// CDevAudioControl::BufferErrorEvent
// -----------------------------------------------------------------------------
//
void CDevAudioControl::BufferErrorEvent()
{
ASSERT(EFalse); //This should never happen
}
// End of file