diff -r 000000000000 -r 40261b775718 devsound/devsoundrefplugin/src/controller/audio/MmfAudioToneController.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/devsound/devsoundrefplugin/src/controller/audio/MmfAudioToneController.cpp Tue Feb 02 01:56:55 2010 +0200 @@ -0,0 +1,1029 @@ +// Copyright (c) 2003-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 +#include +#include +#include +#include +#include +#include "MmfAudioToneController.h" +#include + +/* + A list of panic codes for the Audio Tone Controller +@internalTechnology + + TMmfAudioToneControllerPanics is an enumeration with the following entries: + EBadArgument indicates a bad argument + EBadState indicates a state viaolation + EBadInvariant indicates an invariant violation + EBadReset indicates failed reset + EPostConditionViolation indicates a post condition violation +*/ +enum TMmfAudioToneControllerPanics + { + EBadArgument, + EBadState, + EBadInvariant, + EBadReset, + EPostConditionViolation, + EBadCall, + ENoDataSource, + ENoDataSink, + EMessageAlreadyBeingProcessed, + ENoMessageToProcess, + EStateNotReadyToPlay, + EStateNotConstructed, + EBadStateToGetDataSource, + EBadStateToGetDataSink, + EBadStateForPrime, + EStateNotPrimed, + EBadResetState, + EBadStateToReset, + EBadPlayState, + EBadPauseState, + EBadStateToPause, + EBadStateToStop, + EBadStopState, + ENotReadyForDataSourceRemoval, + EBadDataSourceRemoval, + ENotReadyForDataSinkRemoval, + EBadDataSinkRemoval, + ENotReadyForCustomCommand, + EBadStateAfterNegotiate, + EBadStateToSetPriority, + EBadPriorityState, + EBadInitializeState, + EBadStateToSetVolume, + EBadStateAfterVolumeSet, + EBadStateToGetMaxVolume, + EBadStateAfterGetMaxVolume, + EBadStateToGetVolume, + EBadStateAfterGetVolume, + EBadStateToSetVolumeRamp, + EBadStateAfterSetVolumeRamp, + EBadStateToSetBalance, + EBadStateAfterSetBalance, + EBadStateToGetBalance, + EBadStateAfterGetBalance, + EBadStateForTransition, + EBadStateAfterTransition, + EStateNotValid, + }; + + +/** + Instantiates a new Audio Tone Controller. Usually invoked from ECom + + @internalTechnology + @return CMMFController* bas class for all plugin controllers + */ +CMMFController* CMMFAudioToneController::NewL() + { + CMMFAudioToneController* self = new(ELeave) CMMFAudioToneController; + CleanupStack::PushL(self); + self->ConstructL(); + CleanupStack::Pop( self ); + return STATIC_CAST( CMMFController*, self ); + } + + + +/** +2nd Phase constructor + +@internalComponent +*/ +void CMMFAudioToneController::ConstructL() + { + iSourceAndSinkAdded = EFalse; + + // Construct custom command parsers + CMMFAudioPlayDeviceCustomCommandParser* audPlayDevParser = CMMFAudioPlayDeviceCustomCommandParser::NewL(*this); + CleanupStack::PushL(audPlayDevParser); + AddCustomCommandParserL(*audPlayDevParser); + CleanupStack::Pop( audPlayDevParser );//audPlayDevParser + + CMMFAudioPlayControllerCustomCommandParser* audPlayConParser = CMMFAudioPlayControllerCustomCommandParser::NewL(*this); + CleanupStack::PushL(audPlayConParser); + AddCustomCommandParserL(*audPlayConParser); + CleanupStack::Pop(audPlayConParser);//audPlayConParser + + CMMFAudioPlayControllerSetRepeatsCustomCommandParser* audPlayConSetRepeatsParser = CMMFAudioPlayControllerSetRepeatsCustomCommandParser::NewL(*this); + CleanupStack::PushL(audPlayConSetRepeatsParser); + AddCustomCommandParserL(*audPlayConSetRepeatsParser); + CleanupStack::Pop(audPlayConSetRepeatsParser); + + // [ assert the invariant now that we are constructed ] + __ASSERT_ALWAYS( Invariant(), Panic( EStateNotConstructed)); + } + + +/** +1st Phase constructor + +@internalComponent +*/ + +CMMFAudioToneController::CMMFAudioToneController() : iState(EStopped) + { + } + +/** +Destructor + +@internalTechnology +*/ +CMMFAudioToneController::~CMMFAudioToneController() + { + delete iMMFDevSound; + delete iToneSequenceData; + delete iMessage; + } + +/** +Adds a data source to the controller + +@internalTechnology + +@param aSource will provide the data the controller plays +*/ +void CMMFAudioToneController::AddDataSourceL(MDataSource& aSource) + { + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic( EBadStateToGetDataSource)); + + // [ precondition that the controller is stopped ] + if( State() != EStopped ) + User::Leave( KErrNotReady ); + + //[ precondition iData source is not already configured ] + if (iDataSource) + User::Leave(KErrAlreadyExists); + + //Only works with files or descriptors + if ((aSource.DataSourceType() != KUidMmfFileSource ) && (aSource.DataSourceType() != KUidMmfDescriptorSource)) + User::Leave( KErrNotSupported ) ; + + + //extract the tone data into a buffer ready to play. + iToneSequenceData = CMMFDataBuffer::NewL(STATIC_CAST(CMMFClip*, &aSource)->Size()); + + aSource.SourcePrimeL(); + STATIC_CAST(CMMFClip*, &aSource)->ReadBufferL(iToneSequenceData,0); + aSource.SourceStopL(); + + + //[ its now safe to set the source ] + iDataSource = &aSource ; + + //[ assert the post condition ] + __ASSERT_ALWAYS(iDataSource, Panic(EMMFAudioControllerPanicDataSourceDoesNotExist)); + + iDataSource->SetSourcePrioritySettings(iPrioritySettings); + } + + + +/** +Adds a data sink to the controller + +@internalTechnology + +@param aSink will accept the data the controller plays +*/ +void CMMFAudioToneController::AddDataSinkL(MDataSink& aSink) + { + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic( EBadStateToGetDataSink)); + + // [ precondition that the controller is stopped ] + if( State() != EStopped ) + User::Leave( KErrNotReady ); + + // [ assert precondition that sink does not exist ] + if (iMMFDevSound) + User::Leave(KErrAlreadyExists); + + //Only support playing to audio output + if (aSink.DataSinkType() != KUidMmfAudioOutput) + User::Leave( KErrNotSupported ); + + iMMFDevSound = CMMFDevSound::NewL(); + + // [ assert post conditions that a sink has been added ] + __ASSERT_ALWAYS(iMMFDevSound, Panic(EMMFAudioControllerPanicDataSinkDoesNotExist)); + } + +/** +Primes the controller, ready for playing + +@internalTechnology + +@param aMessage allows response to client upon completion or error +*/ +void CMMFAudioToneController::PrimeL(TMMFMessage& aMessage) + { + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic( EBadStateForPrime)); + + //[ assert the precondition ( in a friendly way for this api + // that we are either stopped or primed already ] + if(!(( State() == EStopped ) || (State() == EPrimed ))) + User::Leave( KErrNotReady ); + + // [ precondition we have a data source & sink and aren't already processing a message] + __ASSERT_ALWAYS( iDataSource, Panic( ENoDataSource)); + __ASSERT_ALWAYS( iMMFDevSound, Panic( ENoDataSink)); + __ASSERT_ALWAYS( !iMessage, Panic( EMessageAlreadyBeingProcessed )); + + if (iState == EStopped) + { + + iMessage = new(ELeave) TMMFMessage(aMessage); //store message + __ASSERT_ALWAYS( iMessage, Panic( EPostConditionViolation )); //check if message created sucessfully + SetState(EPriming); + + TRAPD(err,NegotiateL()); + if(err != KErrNone) + { + SetState( EStopped ); + delete iMessage; + iMessage = NULL; + User::Leave(err); + } + } + + __ASSERT_ALWAYS( Invariant(), Panic( EStateNotPrimed ) ); + + } + +/** +Primes the controller, ready for playingAdds a data sink to the controller + +@internalTechnology +*/ +void CMMFAudioToneController::PrimeL() + { + Panic(EBadCall); + } + +/** +This method resets the controller + +@internalTechnology +*/ +void CMMFAudioToneController::ResetL() + { + __ASSERT_ALWAYS( Invariant(), Panic( EBadStateToReset ) ); + + // Stop recording if it's not stopped, + if (State() != EStopped) + { + StopL(); + } + + //[ ensure loggoff of source and sink ] + iDataSource = NULL ; + delete iMMFDevSound; iMMFDevSound = NULL ; + iSourceAndSinkAdded = EFalse; + delete iMessage; + iMessage = NULL; + + + // [ assert the invariant] + __ASSERT_ALWAYS( Invariant(), Panic( EBadResetState ) ); + + __ASSERT_ALWAYS( ResetPostCondition(), Panic( EBadReset )); + __ASSERT_ALWAYS( Invariant(), Panic(EBadState)); + } + +/** +This function determnines if the reset post condition is valid + +@internalComponent +*/ +TBool CMMFAudioToneController::ResetPostCondition() const + { + TBool result = EFalse ; + if((iMMFDevSound == NULL) && + (iDataSource == NULL) && + (State() == EStopped)) + { + result = ETrue; + } + return result; + } + + +/** +Start playing the audio tone, passing the data to Dev Sound + +The controller will be put into the EPlaying state + +@internalTechnology +*/ +void CMMFAudioToneController::PlayL() + { + // [ assert the precondition that the + // play command is only activated in the primed state] + if ( State() != EPrimed && State() != EPausePlaying) + User::Leave(KErrNotReady); + + // [ assert the Invariant ] + __ASSERT_ALWAYS( Invariant(), Panic(EStateNotReadyToPlay)); + + if(State() == EPausePlaying && iIsResumeSupported) + { + User::LeaveIfError(iMMFDevSound->Resume()); + } + else + { + iMMFDevSound->PlayToneSequenceL(iToneSequenceData->Data()); + } + + SetState( EPlaying ); + + //[ assert the post condition we are playing ] + __ASSERT_ALWAYS( (State() == EPlaying ), Panic( EBadState)); + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic(EBadPlayState)); + } + +/** +This should Pause playing of the audio tone. HOWEVER, this is not possible with a +tone sequence. This method is therefore provided as a NOP purely to allow audio +clients to operate correctly. + +The controller will be put into the EPrimed state + +@internalTechnology + */ +void CMMFAudioToneController::PauseL() + { + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic(EBadStateToPause)); + + __ASSERT_ALWAYS(iMMFDevSound, Panic(EMMFAudioControllerPanicDataSinkDoesNotExist)); + + if(iIsResumeSupported) + { + iMMFDevSound->Pause(); + SetState(EPausePlaying); + } + else + { + // If Resume is not supported + // this method can't do anything, as we have no interface to restart DevSound + // after pausing a tone. It need to be here however as client utility does + // Pause() Stop() when stopping. + SetState(EPrimed); + } + + //[ assert the post condition we are stopped ] + __ASSERT_ALWAYS( (State() == EPrimed || State() == EPausePlaying), Panic( EBadState)); + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic(EBadPauseState)); + } + +/** +This stops the tone that is currently playing +The controller will be put into the EStopped state + +@internalTechnology +*/ +void CMMFAudioToneController::StopL() + { + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic(EBadStateToStop)); + + // [ precondition that we are not already stopped + // && if we are stopped do nothing. + // Due to the asynchronous nature of the controller + // interaction the response to stopped when stopped + // should not be an error ] + if (State() != EStopped) + { + //[ update state to stopped propogate to devsound ] + iMMFDevSound->Stop(); + SetState(EStopped); + } + + //[ assert the post condition we are stopped ] + __ASSERT_ALWAYS( (State() == EStopped), Panic( EBadState)); + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic(EBadStopState)); + } + + +/** +Removes a data source form the controller + +@internalTechnology + +@param aDataSource The source that is to be removed. +*/ +void CMMFAudioToneController::RemoveDataSourceL(MDataSource& aDataSource ) + { + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic(ENotReadyForDataSourceRemoval) ); + + //[ precondition is that we have a data source ] + if( !iDataSource ) + User::Leave(KErrNotReady); + + //[precondition the data source is the data source we have] + if( iDataSource != &aDataSource ) + User::Leave(KErrArgument); + + //[ the controller is in the stopped state ] + if(State() != EStopped) + User::Leave(KErrNotReady); + + //[ remove the data sink from the controller and delete the format] + if( iSourceAndSinkAdded ) + { + iMMFDevSound->Stop(); + iSourceAndSinkAdded = EFalse ; + } + + iDataSource = NULL ; + + // [ assert postcondition we are stopped ] + __ASSERT_ALWAYS( (State() == EStopped), Panic(EPostConditionViolation) ); + + //[ assert postcondition the SourceAndSinkAdded is false ] + __ASSERT_ALWAYS( !iSourceAndSinkAdded, Panic( EPostConditionViolation )); + + //[ assert postcondition the data sink is null ] + __ASSERT_ALWAYS( (iDataSource == NULL ), Panic( EPostConditionViolation )); + + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic(EBadDataSourceRemoval)); + } + + +/** +Removes a data sink form the controller + +@internalTechnology + +@param aDataSink The sink that is to be removed. We donot +use this value, as we only support a single sink. +*/ +void CMMFAudioToneController::RemoveDataSinkL(MDataSink& /*aDataSink*/) + { + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic(ENotReadyForDataSinkRemoval) ); + + //[ precondition is that we have a data sink ] + if(!iMMFDevSound) + User::Leave(KErrNotReady); + + //[ the controller is in the stopped state ] + if(State() != EStopped) + User::Leave(KErrNotReady); + + //[ remove the data sink from the controller and delete the format] + if(iSourceAndSinkAdded) + { + iMMFDevSound->Stop(); + iSourceAndSinkAdded = EFalse; + } + + delete iMMFDevSound; iMMFDevSound = NULL; + + + // [ assert postcondition we are stopped ] + __ASSERT_ALWAYS( (State() == EStopped), Panic(EPostConditionViolation) ); + + //[ assert postcondition the SourceAndSinkAdded is false ] + __ASSERT_ALWAYS( !iSourceAndSinkAdded, Panic( EPostConditionViolation )); + + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic(EBadDataSinkRemoval)); + } + +/** +Handles a CustomCommand for the controller. This controller doesn't support Custom Commands + +@internalTechnology +@param aMessage +*/ +void CMMFAudioToneController::CustomCommand(TMMFMessage& aMessage) + { + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic(ENotReadyForCustomCommand)); + // [ We do not have any custom commands ] + aMessage.Complete(KErrNotSupported); + } + +/** +Configures Dev Sound, ready for playing. + +@internalComponent +*/ +void CMMFAudioToneController::NegotiateL() + { + if (!iMMFDevSound) + Panic(EMMFAudioOutputDevSoundNotLoaded); + + iMMFDevSound->InitializeL(*this, EMMFStateTonePlaying); + iMMFDevSound->SetPrioritySettings(iPrioritySettings); + + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic(EBadStateAfterNegotiate)); + } + +/** +Set the priority settings that this controller should use to access Dev Sound + +@internalTechnology +@param aPrioritySettings The requires priority settings +*/ +void CMMFAudioToneController::SetPrioritySettings(const TMMFPrioritySettings& aPrioritySettings) + { + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic(EBadStateToSetPriority)); + + //[ assert the precondition ] + if(State() != EStopped) + { + ASSERT(EFalse); // used to leave here with KErrNotReady + return; + } + + //[ update the priority settings of the controller] + iPrioritySettings = aPrioritySettings; + + if (iMMFDevSound) + { + iMMFDevSound->SetPrioritySettings(iPrioritySettings); + } + + __ASSERT_ALWAYS( Invariant(), Panic(EBadPriorityState)); + } + + + +/** +This method is called by DevSound after initialization, indicating that it has completed and +whether there was an error + +@internalTechnology +@param aError the error supplied by Dev Sound +*/ +void CMMFAudioToneController::InitializeComplete(TInt aError) + { + //[ assert the state is EPriming ] + __ASSERT_ALWAYS( ( State() == EPriming ), Panic( EBadState )); + __ASSERT_ALWAYS( iMessage, Panic( ENoMessageToProcess )); + + if(aError != KErrNone) + { + SetState( EStopped ); + iMessage->Complete(aError); + } + else + { + SetState( EPrimed ); + iMessage->Complete(aError); + iIsResumeSupported = iMMFDevSound->IsResumeSupported(); + } + + delete iMessage; + iMessage = NULL; + + // [ assert the invariant] + __ASSERT_ALWAYS( Invariant(), Panic( EBadInitializeState ) ); + } + + +/** +This method is called by DevSound after it has finished playing a tone sequence, indicating +whether there was an error + +@internalTechnology +@param aError the error supplied by DevSound +*/ +void CMMFAudioToneController::ToneFinished(TInt aError) + { + // NB KErrInUse, KErrDied OR KErrAccessDenied may be returned + // to indicate that the sound device is in use by another higher + // priority client. + if (aError == KErrCancel || aError == KErrInUse || + aError == KErrDied || aError == KErrAccessDenied) + return; + + if (aError == KErrUnderflow) + aError = KErrNone; + + if (State() != EStopped) + { + iMMFDevSound->Stop(); + SetState( EStopped ); + } + + //now send event to client... + TMMFEvent event; + event.iEventType = KMMFEventCategoryPlaybackComplete; + event.iErrorCode = aError; + DoSendEventToClient(event); + } + + + +/** +Called my DevSound to indicate we have been thrown off H/W by a higher priority + +@internalTechnology +@param aEvent contains the reason we have been contacted by DevSound +*/ +void CMMFAudioToneController::SendEventToClient(const TMMFEvent& aEvent) + { + if(State() == EPlaying) + SetState(EStopped); + + DoSendEventToClient(aEvent); + } + + + + +/** +Sets the playback volume + +@internalTechnology +@param aVolume the required volume +*/ +void CMMFAudioToneController::MapdSetVolumeL(TInt aVolume) + { + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic(EBadStateToSetVolume)); + + // [ precondition is true for state + // we can set the volume in any state ] + + //[ precondition we have a data sink ] + if (!iMMFDevSound) + User::Leave(KErrNotReady); + + + // [ assert the precondition that aVolume is in range ] + TInt maxVolume = iMMFDevSound->MaxVolume(); + if( ( aVolume < 0 ) || ( aVolume > maxVolume )) + User::Leave(KErrArgument); + + //[ set the volume on the device ] + iMMFDevSound->SetVolume(aVolume); + + //[ assert the post condition volume is equal to a volume] + TInt soundVolume = 0; + soundVolume = iMMFDevSound->Volume(); + + __ASSERT_ALWAYS( ( soundVolume == aVolume), Panic(EPostConditionViolation)); + + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic(EBadStateAfterVolumeSet)); + } + +/** +Gets the maximum level the playback volume can be set to + +@internalTechnology +@param aMaxVolume contains the maximum volume setting +*/ +void CMMFAudioToneController::MapdGetMaxVolumeL(TInt& aMaxVolume) + { + // [ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic(EBadStateToGetMaxVolume)); + + //[ precondition we have a data sink ] + if (!iMMFDevSound) + User::Leave(KErrNotReady); + + //[ get the volume from the device ] + aMaxVolume = iMMFDevSound->MaxVolume(); + + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic(EBadStateAfterGetMaxVolume)); + + } + + +/** +Gets the current playback volume + +@internalTechnology +@param aVolume the current volume +*/ +void CMMFAudioToneController::MapdGetVolumeL(TInt& aVolume) + { + // [ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic(EBadStateToGetVolume)); + + //[ precondition that we have a data sink ] + if (!iMMFDevSound) + User::Leave(KErrNotReady); + + aVolume = iMMFDevSound->Volume(); + + // [ assert precondition that the volume is in range + // 0.. aMaxVolume ] + TInt aMaxVolume = iMMFDevSound->MaxVolume(); + __ASSERT_ALWAYS( (aVolume <= aMaxVolume), Panic(EBadState)); + __ASSERT_ALWAYS( (aVolume >= 0), Panic(EBadState)); + + // [ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic(EBadStateAfterGetVolume)); + + } + +/** +Sets the duration over which the volume should increase + +@internalTechnology +@param aRampDuration the time over which the volume should ramp +*/ +void CMMFAudioToneController::MapdSetVolumeRampL(const TTimeIntervalMicroSeconds& aRampDuration) + { + // [ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic(EBadStateToSetVolumeRamp)); + + //[ precondition that we have a data sink ] + if (!iMMFDevSound) + User::Leave(KErrNotReady); + + iMMFDevSound->SetVolumeRamp(aRampDuration); + + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic(EBadStateAfterSetVolumeRamp)); + + } + + +/** +Sets the balance of the tone playback + +@internalTechnology +@param aBalance the required balance level (KMMFBalanceMaxLeft <= aBalance <= KMMFBalanceMaxRight) +*/ +void CMMFAudioToneController::MapdSetBalanceL(TInt aBalance) + { + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic( EBadStateToSetBalance)); + + // [ precondition is that we have a data sink ] + if (!iMMFDevSound) + User::Leave(KErrNotReady); + + + // [ separate out left and right balance ] + TInt left = 0; + TInt right = 0; + CalculateLeftRightBalance( left, right, aBalance ); + + //[ set the balance ] + iMMFDevSound->SetPlayBalanceL(left, right); + + // [assert the post condition that the balance is set correctly] + TInt rightBalance = 0; + TInt leftBalance = 0; + iMMFDevSound->GetPlayBalanceL(leftBalance, rightBalance); + + //[ assert post condition holds] + TBool postCondition = (( rightBalance == right) && ( leftBalance == left)); + __ASSERT_ALWAYS( postCondition, Panic( EPostConditionViolation ) ); + + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic( EBadStateAfterSetBalance)); + } + +/** +Converts the balance from a range to a left/right form. + +Balance is provided to devsound using left and right levels, but supplied to the controller as a range +(KMMFBalanceMaxLeft --> KMMFBalanceMaxRight). This method converts the range into a left/right form + +@internalComponent + +@param aLeft set to the left setting +@param aRight set to the right setting +@param aBalance the range required +*/ +void CMMFAudioToneController::CalculateLeftRightBalance( TInt& aLeft, TInt& aRight, TInt aBalance ) const + { + // Check the balance is within limits & modify to min or max values if necessary + if (aBalance < KMMFBalanceMaxLeft) + aBalance = KMMFBalanceMaxLeft; + if (aBalance > KMMFBalanceMaxRight) + aBalance = KMMFBalanceMaxRight; + + //[ Now separate percentage balances out from aBalance ] + aLeft = (100 * (aBalance-KMMFBalanceMaxRight)) / (KMMFBalanceMaxLeft-KMMFBalanceMaxRight); + aRight = 100 - aLeft; + + //[ assert post condition that left and right are within range ] + __ASSERT_ALWAYS( ( (aLeft <= 100) && (aLeft >= 0) ), Panic(EPostConditionViolation)); + __ASSERT_ALWAYS( ( (aRight <= 100) && (aRight >= 0) ), Panic(EPostConditionViolation)); + } + + +/** +Gets the balance of the tone playback + +@internalTechnology +@param aBalance set to the current balance level (KMMFBalanceMaxLeft <= aBalance <= KMMFBalanceMaxRight) +*/ +void CMMFAudioToneController::MapdGetBalanceL(TInt& aBalance) + { + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic(EBadStateToGetBalance)); + + //[ precondition that we have a sink] + if (!iMMFDevSound) + User::Leave(KErrNotReady); + + + TInt left = 50; // arbitrary values + TInt right = 50; + iMMFDevSound->GetPlayBalanceL(left, right); + + CalculateBalance( aBalance, left, right ); + + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic(EBadStateAfterGetBalance)); + } + + +/** +Converts the balance from a left/right form to a range. + +Balance is obtained from DevSound using left and right levels, but supplied to the client as a range +(KMMFBalanceMaxLeft --> KMMFBalanceMaxRight). + +@internalComponent + +@param aLeft the current left setting +@param aRight current right setting +@param aBalance set to the balance range +*/ +void CMMFAudioToneController::CalculateBalance( TInt& aBalance, TInt aLeft, TInt aRight ) const + { + //[ assert pre conditions ] + __ASSERT_ALWAYS( (( aLeft + aRight ) == 100 ), Panic( EBadArgument )); + __ASSERT_ALWAYS( (( 0 <= aLeft) && ( 100 >= aLeft)), Panic( EBadArgument) ); + __ASSERT_ALWAYS( (( 0 <= aRight) && ( 100 >= aRight)), Panic( EBadArgument) ); + + aBalance = (aLeft * (KMMFBalanceMaxLeft-KMMFBalanceMaxRight))/100 + KMMFBalanceMaxRight; + + //[ assert post condition that aBalance is within limits ] + __ASSERT_ALWAYS( !(aBalance < KMMFBalanceMaxLeft || aBalance > KMMFBalanceMaxRight), Panic(EBadArgument)); + + } + + + + +/** +The function validates a state transition from iState to aState and +returns ETrue if the transition is allowed. + +@internalComponent +@param TControllerState +@return Valid controller state or not +*/ +TBool CMMFAudioToneController::IsValidStateTransition( TControllerState aState ) const + { + TBool result = ETrue ; + //[ assert the precondition that aState is a valid State ] + __ASSERT_ALWAYS( IsValidState(aState), Panic( EBadArgument ) ); + //[ assert the invariant that iState is a valid State ] + __ASSERT_ALWAYS( Invariant(), Panic( EBadStateForTransition )); + + // [ check the valid state transitions ] + // the only invalid transition is + // stopped to playing + if( ( iState == EStopped ) && ( aState == EPlaying )) + { + result = EFalse ; + } + + //[ assert the invariant that iState is a valid State ] + __ASSERT_ALWAYS( Invariant(), Panic( EBadStateAfterTransition )); + + return result ; + } + +/* +This function returns whether the invariant is valid + +@internalComponent +@return Is the class in a good condition +*/ +TBool CMMFAudioToneController::Invariant() const + { + //[ The invariant is for now defined + // as simply being in the correct state + return IsValidState( iState); + } + +/* +This function sets the state of the controller. + +@internalComponent +@return Whether ths state transition is valid +*/ +TBool CMMFAudioToneController::SetState(TControllerState aState) + { + TBool result = ETrue; + //[ assert the precondition that the state is a valid state ] + __ASSERT_ALWAYS( IsValidState( aState), Panic( EBadArgument ) ); + //[ assert the invariant the current state is valid ] + __ASSERT_ALWAYS( Invariant(), Panic( EStateNotValid ) ); + //[ only allow valid state transitions ] + if( IsValidStateTransition( aState ) ) + { + //[ valid state transition set the state] + iState = aState ; + } + else + { + //[ invalid state transition return EFalse ] + result = EFalse; + } + // [ assert the invariant on the state ] + __ASSERT_ALWAYS( Invariant(), Panic( EBadState )); + + return result ; + } + +/* +checks whether a state is valid + +@internalComponent +@return Is the state a valid one +*/ +TBool CMMFAudioToneController::IsValidState( TControllerState aState ) const + { + TBool result = EFalse; + if(( aState >= EStopped ) && ( aState <= EPlaying )) + { + result = ETrue; + } + return result; + } + +/** +The function State returns the current state of the audio controller + +@internalComponent +@return State of the controller +*/ +CMMFAudioToneController::TControllerState CMMFAudioToneController::State() const + { + __ASSERT_ALWAYS( Invariant(), Panic( EBadState ) ); + return iState; + } + + +/** +* MapcSetRepeatsL +* @param aRepeatNumberOfTimes +* @param aTrailingSilence +* +*/ +TInt CMMFAudioToneController::MapcSetRepeats(TInt aRepeatNumberOfTimes, const TTimeIntervalMicroSeconds& aTrailingSilence) + { + TInt err = KErrNone; + if (!iMMFDevSound) + { + return KErrNotReady; + } + else + { + if(iMMFDevSound->QueryIgnoresUnderflow()) + { + iMMFDevSound->SetToneRepeats(aRepeatNumberOfTimes, aTrailingSilence); + } + else + { + err = KErrNotSupported; + } + } + return err; + }