mmfenh/advancedaudiocontroller/audiotonecontrollerplugin/src/mmfaudiotonecontroller.cpp
changeset 0 71ca22bcf22a
child 20 b67dd1fc57c5
child 45 095bea5f582e
equal deleted inserted replaced
-1:000000000000 0:71ca22bcf22a
       
     1 // Copyright (c) 2003-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 //
       
    15 
       
    16 
       
    17 #include <mmf/server/mmfformat.h>
       
    18 #include <mmf/server/mmfclip.h>
       
    19 #include <mdaaudiosampleeditor.h>
       
    20 #include <mmfcontrollerimplementationuids.hrh>
       
    21 #include <mmf/common/mmffourcc.h>
       
    22 #include <mmf/common/mmfpaniccodes.h>
       
    23 #include "mmfaudiotonecontroller.h"
       
    24 #include <mmf/server/mmfaudiooutput.h>
       
    25 
       
    26 /*
       
    27  A list of panic codes for the Audio Tone Controller
       
    28 @internalTechnology
       
    29 
       
    30  TMmfAudioToneControllerPanics is an enumeration with the following entries:
       
    31  EBadArgument indicates a bad argument
       
    32  EBadState indicates a state viaolation
       
    33  EBadInvariant indicates an invariant violation
       
    34  EBadReset indicates failed reset
       
    35  EPostConditionViolation indicates a post condition violation
       
    36 */
       
    37 enum TMmfAudioToneControllerPanics
       
    38 	{
       
    39 	EBadArgument,
       
    40 	EBadState,
       
    41 	EBadInvariant,
       
    42 	EBadReset,
       
    43 	EPostConditionViolation,
       
    44 	EBadCall,
       
    45 	ENoDataSource,
       
    46 	ENoDataSink,
       
    47 	EMessageAlreadyBeingProcessed,
       
    48 	ENoMessageToProcess,
       
    49 	EStateNotReadyToPlay,
       
    50 	EStateNotConstructed,
       
    51 	EBadStateToGetDataSource,
       
    52 	EBadStateToGetDataSink,
       
    53 	EBadStateForPrime,
       
    54 	EStateNotPrimed,
       
    55 	EBadResetState,
       
    56 	EBadStateToReset,
       
    57 	EBadPlayState,
       
    58 	EBadPauseState,
       
    59 	EBadStateToPause,
       
    60 	EBadStateToStop,
       
    61 	EBadStopState,
       
    62 	ENotReadyForDataSourceRemoval,
       
    63 	EBadDataSourceRemoval,
       
    64 	ENotReadyForDataSinkRemoval,
       
    65 	EBadDataSinkRemoval,
       
    66 	ENotReadyForCustomCommand,
       
    67 	EBadStateAfterNegotiate,
       
    68 	EBadStateToSetPriority,
       
    69 	EBadPriorityState,
       
    70 	EBadInitializeState,
       
    71 	EBadStateToSetVolume,
       
    72 	EBadStateAfterVolumeSet,
       
    73 	EBadStateToGetMaxVolume,
       
    74 	EBadStateAfterGetMaxVolume,
       
    75 	EBadStateToGetVolume,
       
    76 	EBadStateAfterGetVolume,
       
    77 	EBadStateToSetVolumeRamp,
       
    78 	EBadStateAfterSetVolumeRamp,
       
    79 	EBadStateToSetBalance,
       
    80 	EBadStateAfterSetBalance,
       
    81 	EBadStateToGetBalance,
       
    82 	EBadStateAfterGetBalance,
       
    83 	EBadStateForTransition,
       
    84 	EBadStateAfterTransition,
       
    85 	EStateNotValid,
       
    86 	};
       
    87 
       
    88 
       
    89 /**
       
    90  Instantiates a new Audio Tone Controller. Usually invoked from ECom
       
    91  
       
    92  @internalTechnology
       
    93  @return CMMFController* bas class for all plugin controllers
       
    94  */
       
    95 CMMFController* CMMFAudioToneController::NewL()
       
    96 	{
       
    97 	CMMFAudioToneController* self = new(ELeave) CMMFAudioToneController;
       
    98 	CleanupStack::PushL(self);
       
    99 	self->ConstructL();
       
   100 	CleanupStack::Pop( self );
       
   101 	return STATIC_CAST( CMMFController*, self );
       
   102 	}
       
   103 
       
   104 
       
   105 
       
   106 /**
       
   107 2nd Phase constructor
       
   108 
       
   109 @internalComponent
       
   110 */
       
   111 void CMMFAudioToneController::ConstructL()
       
   112 	{
       
   113 	iSourceAndSinkAdded = EFalse;
       
   114 
       
   115 	// Construct custom command parsers
       
   116 	CMMFAudioPlayDeviceCustomCommandParser* audPlayDevParser = CMMFAudioPlayDeviceCustomCommandParser::NewL(*this);
       
   117 	CleanupStack::PushL(audPlayDevParser);
       
   118 	AddCustomCommandParserL(*audPlayDevParser);
       
   119 	CleanupStack::Pop( audPlayDevParser );//audPlayDevParser
       
   120 
       
   121 	CMMFAudioPlayControllerCustomCommandParser* audPlayConParser = CMMFAudioPlayControllerCustomCommandParser::NewL(*this);
       
   122 	CleanupStack::PushL(audPlayConParser);
       
   123 	AddCustomCommandParserL(*audPlayConParser);
       
   124 	CleanupStack::Pop(audPlayConParser);//audPlayConParser
       
   125 	
       
   126 	CMMFAudioPlayControllerSetRepeatsCustomCommandParser* audPlayConSetRepeatsParser = CMMFAudioPlayControllerSetRepeatsCustomCommandParser::NewL(*this);
       
   127 	CleanupStack::PushL(audPlayConSetRepeatsParser);
       
   128 	AddCustomCommandParserL(*audPlayConSetRepeatsParser);
       
   129 	CleanupStack::Pop(audPlayConSetRepeatsParser);
       
   130 	
       
   131 	// [ assert the invariant now that we are constructed ]
       
   132 	__ASSERT_ALWAYS( Invariant(), Panic( EStateNotConstructed));
       
   133 	}
       
   134 
       
   135 
       
   136 /**
       
   137 1st Phase constructor
       
   138 
       
   139 @internalComponent
       
   140 */
       
   141 
       
   142 CMMFAudioToneController::CMMFAudioToneController() : iState(EStopped)
       
   143 	{
       
   144 	}
       
   145 
       
   146 /**
       
   147 Destructor
       
   148 
       
   149 @internalTechnology
       
   150 */
       
   151 CMMFAudioToneController::~CMMFAudioToneController()
       
   152 	{
       
   153 	delete iMMFDevSound;
       
   154 	delete iToneSequenceData;
       
   155 	delete iMessage;
       
   156 	}
       
   157 
       
   158 /**
       
   159 Adds a data source to the controller 
       
   160 
       
   161 @internalTechnology
       
   162 
       
   163 @param aSource will provide the data the controller plays
       
   164 */
       
   165 void CMMFAudioToneController::AddDataSourceL(MDataSource& aSource)
       
   166 	{
       
   167 	//[ assert the invariant ]
       
   168 	__ASSERT_ALWAYS( Invariant(), Panic( EBadStateToGetDataSource));
       
   169 
       
   170 	// [ precondition that the controller is stopped ]
       
   171     if( State() != EStopped )
       
   172 		User::Leave( KErrNotReady );
       
   173 	
       
   174 	//[ precondition iData source is not already configured ]
       
   175 	if (iDataSource)
       
   176 		User::Leave(KErrAlreadyExists);
       
   177 
       
   178 	//Only works with files or descriptors
       
   179 	if ((aSource.DataSourceType() != KUidMmfFileSource ) && (aSource.DataSourceType() != KUidMmfDescriptorSource))
       
   180 		User::Leave( KErrNotSupported ) ;
       
   181 
       
   182 
       
   183 	//extract the tone data into a buffer ready to play.
       
   184 	iToneSequenceData = CMMFDataBuffer::NewL(STATIC_CAST(CMMFClip*, &aSource)->Size());
       
   185 
       
   186 	aSource.SourcePrimeL();
       
   187 	STATIC_CAST(CMMFClip*, &aSource)->ReadBufferL(iToneSequenceData,0);
       
   188 	aSource.SourceStopL();
       
   189 
       
   190 
       
   191 	//[ its now safe to set the source ]
       
   192 	iDataSource = &aSource ;
       
   193 
       
   194 	//[ assert the post condition ]
       
   195 	__ASSERT_ALWAYS(iDataSource, Panic(EMMFAudioControllerPanicDataSourceDoesNotExist));
       
   196 
       
   197 	iDataSource->SetSourcePrioritySettings(iPrioritySettings);
       
   198 	}
       
   199 
       
   200 
       
   201 
       
   202 /**
       
   203 Adds a data sink to the controller 
       
   204 
       
   205 @internalTechnology
       
   206 
       
   207 @param aSink will accept the data the controller plays
       
   208 */
       
   209 void CMMFAudioToneController::AddDataSinkL(MDataSink& aSink)
       
   210 	{
       
   211 	//[ assert the invariant ]
       
   212 	__ASSERT_ALWAYS( Invariant(), Panic( EBadStateToGetDataSink));
       
   213 
       
   214 	// [ precondition that the controller is stopped ]
       
   215     if( State() != EStopped )
       
   216 		User::Leave( KErrNotReady );
       
   217 
       
   218 	// [ assert precondition that sink does not exist ]
       
   219 	if (iMMFDevSound)
       
   220 		User::Leave(KErrAlreadyExists);
       
   221 
       
   222 	//Only support playing to audio output 
       
   223 	if (aSink.DataSinkType() != KUidMmfAudioOutput)
       
   224 		User::Leave( KErrNotSupported );
       
   225 
       
   226 	iMMFDevSound = CMMFDevSound::NewL();
       
   227 
       
   228 	// [ assert post conditions that a sink has been added ]
       
   229 	__ASSERT_ALWAYS(iMMFDevSound, Panic(EMMFAudioControllerPanicDataSinkDoesNotExist));
       
   230 	}
       
   231 	
       
   232 /**
       
   233 Primes the controller, ready for playing
       
   234 
       
   235 @internalTechnology
       
   236 
       
   237 @param aMessage allows response to client upon completion or error
       
   238 */
       
   239 void CMMFAudioToneController::PrimeL(TMMFMessage& aMessage)
       
   240 	{
       
   241 	//[ assert the invariant ]
       
   242 	__ASSERT_ALWAYS( Invariant(), Panic( EBadStateForPrime));
       
   243 
       
   244 	//[ assert the precondition ( in a friendly way for this api 
       
   245 	// that we are either stopped or primed already ]
       
   246 	if(!(( State() == EStopped ) || (State() == EPrimed )))
       
   247 		User::Leave( KErrNotReady );
       
   248 
       
   249 	// [ precondition we have a data source & sink and aren't already processing a message]
       
   250 	__ASSERT_ALWAYS( iDataSource, Panic( ENoDataSource));
       
   251 	__ASSERT_ALWAYS( iMMFDevSound, Panic( ENoDataSink));
       
   252 	__ASSERT_ALWAYS( !iMessage, Panic( EMessageAlreadyBeingProcessed ));
       
   253 
       
   254 	if (iState == EStopped)
       
   255 		{
       
   256 	
       
   257 		iMessage = new(ELeave) TMMFMessage(aMessage); //store message
       
   258 		__ASSERT_ALWAYS( iMessage, Panic( EPostConditionViolation )); //check if message created sucessfully
       
   259 		SetState(EPriming);
       
   260 
       
   261 		TRAPD(err,NegotiateL());
       
   262 		if(err != KErrNone)
       
   263 			{
       
   264 			SetState( EStopped );
       
   265 			delete iMessage;
       
   266 			iMessage = NULL;
       
   267 			User::Leave(err);
       
   268 			}
       
   269 		}
       
   270 	
       
   271 	__ASSERT_ALWAYS( Invariant(), Panic( EStateNotPrimed ) );
       
   272 
       
   273 	}
       
   274 
       
   275 /**
       
   276 Primes the controller, ready for playingAdds a data sink to the controller 
       
   277 
       
   278 @internalTechnology
       
   279 */
       
   280 void CMMFAudioToneController::PrimeL()
       
   281 	{
       
   282 	Panic(EBadCall);
       
   283 	}
       
   284 
       
   285 /**
       
   286 This method resets the controller
       
   287 
       
   288 @internalTechnology
       
   289 */
       
   290 void CMMFAudioToneController::ResetL()
       
   291 	{
       
   292 	__ASSERT_ALWAYS( Invariant(), Panic( EBadStateToReset ) );
       
   293 
       
   294 	// Stop recording if it's not stopped,
       
   295 	if (State() != EStopped)
       
   296 		{
       
   297 		StopL();
       
   298 		}
       
   299 
       
   300 	//[ ensure loggoff of source and sink ]
       
   301 	iDataSource = NULL ;
       
   302 	delete iMMFDevSound; iMMFDevSound = NULL ;
       
   303 	iSourceAndSinkAdded = EFalse;
       
   304 	delete iMessage;
       
   305 	iMessage = NULL;
       
   306 	
       
   307 
       
   308 	// [ assert the invariant]
       
   309 	__ASSERT_ALWAYS( Invariant(), Panic( EBadResetState ) );
       
   310 
       
   311 	__ASSERT_ALWAYS( ResetPostCondition(), Panic( EBadReset ));
       
   312 	__ASSERT_ALWAYS( Invariant(), Panic(EBadState));
       
   313 	}
       
   314 
       
   315 /**
       
   316 This function determnines if the reset post condition is valid
       
   317 
       
   318 @internalComponent
       
   319 */
       
   320 TBool CMMFAudioToneController::ResetPostCondition() const
       
   321 	{
       
   322      TBool result = EFalse ;
       
   323 	if((iMMFDevSound == NULL)  &&
       
   324 	(iDataSource == NULL)  && 
       
   325 	(State() == EStopped))
       
   326 		{
       
   327          result = ETrue;
       
   328 		}
       
   329     return result;
       
   330 	}
       
   331 
       
   332 
       
   333 /**
       
   334 Start playing the audio tone, passing the data to Dev Sound
       
   335 
       
   336 The controller will be put into the EPlaying state
       
   337 
       
   338 @internalTechnology
       
   339 */
       
   340 void CMMFAudioToneController::PlayL()
       
   341 	{
       
   342 	// [ assert the precondition that the
       
   343 	//   play command is only activated in the primed state]
       
   344 	if ( State() != EPrimed && State() != EPausePlaying)
       
   345 		User::Leave(KErrNotReady);
       
   346 
       
   347 	// [ assert the Invariant ]
       
   348 	__ASSERT_ALWAYS( Invariant(), Panic(EStateNotReadyToPlay));
       
   349 
       
   350 	if(State() == EPausePlaying && iIsResumeSupported)
       
   351 		{
       
   352 		User::LeaveIfError(iMMFDevSound->Resume());
       
   353 		}
       
   354 	else
       
   355 		{
       
   356 		iMMFDevSound->PlayToneSequenceL(iToneSequenceData->Data());	
       
   357 		}
       
   358 	
       
   359 	SetState( EPlaying );
       
   360 	
       
   361 	//[ assert the post condition we are playing ]
       
   362 	__ASSERT_ALWAYS( (State() == EPlaying ), Panic( EBadState));
       
   363 	//[ assert the invariant ]
       
   364 	__ASSERT_ALWAYS( Invariant(), Panic(EBadPlayState));
       
   365 	}
       
   366 
       
   367 /**
       
   368 This should Pause playing of the audio tone. HOWEVER, this is not possible with a 
       
   369 tone sequence. This method is therefore provided as a NOP purely to allow audio
       
   370 clients to operate correctly.
       
   371 
       
   372 The controller will be put into the EPrimed state
       
   373 
       
   374 @internalTechnology
       
   375  */
       
   376 void CMMFAudioToneController::PauseL()
       
   377 	{
       
   378 	//[ assert the invariant ]
       
   379 	__ASSERT_ALWAYS( Invariant(), Panic(EBadStateToPause));
       
   380 
       
   381 	__ASSERT_ALWAYS(iMMFDevSound, Panic(EMMFAudioControllerPanicDataSinkDoesNotExist));
       
   382 
       
   383 	if(iIsResumeSupported)
       
   384 		{
       
   385 		iMMFDevSound->Pause();
       
   386 		SetState(EPausePlaying);
       
   387 		}
       
   388 	else
       
   389 		{
       
   390 		// If Resume is not supported 
       
   391 		// this method can't do anything, as we have no interface to restart DevSound 
       
   392 		// after pausing a tone. It need to be here however as client utility does
       
   393 		// Pause() Stop() when stopping.
       
   394 		SetState(EPrimed);
       
   395 		}
       
   396 
       
   397 	//[ assert the post condition we are stopped ]
       
   398 	__ASSERT_ALWAYS( (State() == EPrimed || State() == EPausePlaying), Panic( EBadState));
       
   399 	//[ assert the invariant ]
       
   400 	__ASSERT_ALWAYS( Invariant(), Panic(EBadPauseState));
       
   401 	}
       
   402 
       
   403 /**
       
   404 This stops the tone that is currently playing
       
   405 The controller will be put into the EStopped state
       
   406 
       
   407 @internalTechnology
       
   408 */
       
   409 void CMMFAudioToneController::StopL()
       
   410 	{
       
   411 	//[ assert the invariant ]
       
   412 	__ASSERT_ALWAYS( Invariant(), Panic(EBadStateToStop));
       
   413 
       
   414 	// [ precondition that we are not already stopped 
       
   415 	// && if we are stopped do nothing.
       
   416 	// Due to the asynchronous nature of the controller
       
   417 	// interaction the response to stopped when stopped 
       
   418 	// should not be an error ]
       
   419 	if (State() != EStopped)
       
   420 		{
       
   421 		//[ update state to stopped propogate to devsound ]
       
   422 		iMMFDevSound->Stop();
       
   423 		SetState(EStopped);
       
   424 		}
       
   425 
       
   426 	//[ assert the post condition we are stopped ]
       
   427 	__ASSERT_ALWAYS( (State() == EStopped), Panic( EBadState));
       
   428 	//[ assert the invariant ]
       
   429 	__ASSERT_ALWAYS( Invariant(), Panic(EBadStopState));
       
   430 	}
       
   431 
       
   432 
       
   433 /**
       
   434 Removes a data source form the controller
       
   435 
       
   436 @internalTechnology
       
   437 
       
   438 @param aDataSource The source that is to be removed.
       
   439 */
       
   440 void CMMFAudioToneController::RemoveDataSourceL(MDataSource& aDataSource )
       
   441 	{
       
   442 	//[ assert the invariant ]
       
   443 	__ASSERT_ALWAYS( Invariant(), Panic(ENotReadyForDataSourceRemoval) );
       
   444 
       
   445 	//[ precondition is that we have a data source ]
       
   446 	if( !iDataSource )
       
   447 		User::Leave(KErrNotReady);
       
   448 
       
   449 	//[precondition the data source is the data source we have]
       
   450 	if( iDataSource != &aDataSource )
       
   451 		User::Leave(KErrArgument);
       
   452 
       
   453 	//[ the controller is in the stopped state ]
       
   454 	if(State() != EStopped)
       
   455 		User::Leave(KErrNotReady);
       
   456 
       
   457 	//[ remove the data sink from the controller and delete the format]
       
   458      if( iSourceAndSinkAdded )
       
   459 		{
       
   460 		iMMFDevSound->Stop();
       
   461 		iSourceAndSinkAdded = EFalse ;
       
   462 		}
       
   463 
       
   464 	 iDataSource = NULL ;
       
   465 		
       
   466 	// [ assert postcondition we are stopped ]
       
   467 	__ASSERT_ALWAYS( (State() == EStopped), Panic(EPostConditionViolation) );
       
   468 
       
   469 	//[ assert postcondition the SourceAndSinkAdded is false ]
       
   470 	__ASSERT_ALWAYS( !iSourceAndSinkAdded, Panic( EPostConditionViolation ));
       
   471 	
       
   472 	//[ assert postcondition the data sink  is null ]
       
   473 	__ASSERT_ALWAYS( (iDataSource == NULL ), Panic( EPostConditionViolation ));
       
   474 
       
   475 	//[ assert the invariant ]
       
   476 	__ASSERT_ALWAYS( Invariant(), Panic(EBadDataSourceRemoval));
       
   477 	}
       
   478 
       
   479 
       
   480 /**
       
   481 Removes a data sink form the controller
       
   482 
       
   483 @internalTechnology
       
   484 
       
   485 @param aDataSink The sink that is to be removed. We donot 
       
   486 use this value, as we only support a single sink. 
       
   487 */
       
   488 void CMMFAudioToneController::RemoveDataSinkL(MDataSink& /*aDataSink*/)
       
   489 	{
       
   490 	//[ assert the invariant ]
       
   491 	__ASSERT_ALWAYS( Invariant(), Panic(ENotReadyForDataSinkRemoval) );
       
   492 
       
   493 	//[ precondition is that we have a data sink ]
       
   494 	if(!iMMFDevSound)
       
   495 		User::Leave(KErrNotReady);
       
   496 
       
   497 	//[ the controller is in the stopped state ]
       
   498 	if(State() != EStopped)
       
   499 		User::Leave(KErrNotReady);
       
   500 
       
   501 	//[ remove the data sink from the controller and delete the format]
       
   502      if(iSourceAndSinkAdded)
       
   503 		{
       
   504 		iMMFDevSound->Stop();
       
   505 		iSourceAndSinkAdded = EFalse;
       
   506 		}
       
   507 
       
   508 	delete iMMFDevSound; iMMFDevSound = NULL;
       
   509 
       
   510 		
       
   511 	// [ assert postcondition we are stopped ]
       
   512 	__ASSERT_ALWAYS( (State() == EStopped), Panic(EPostConditionViolation) );
       
   513 
       
   514 	//[ assert postcondition the SourceAndSinkAdded is false ]
       
   515 	__ASSERT_ALWAYS( !iSourceAndSinkAdded, Panic( EPostConditionViolation ));
       
   516 	
       
   517 	//[ assert the invariant ]
       
   518 	__ASSERT_ALWAYS( Invariant(), Panic(EBadDataSinkRemoval));
       
   519 	}
       
   520 
       
   521 /**
       
   522 Handles a CustomCommand for the controller. This controller doesn't support Custom Commands
       
   523 
       
   524 @internalTechnology
       
   525 @param aMessage
       
   526 */
       
   527 void CMMFAudioToneController::CustomCommand(TMMFMessage& aMessage)
       
   528 	{
       
   529 	//[ assert the invariant ]
       
   530 	__ASSERT_ALWAYS( Invariant(), Panic(ENotReadyForCustomCommand));
       
   531 	// [ We do not have any custom commands ]
       
   532 	aMessage.Complete(KErrNotSupported);
       
   533 	}
       
   534 
       
   535 /**
       
   536 Configures Dev Sound, ready for playing.
       
   537 
       
   538 @internalComponent
       
   539 */
       
   540 void CMMFAudioToneController::NegotiateL()
       
   541 	{
       
   542 	if (!iMMFDevSound)
       
   543 		Panic(EMMFAudioOutputDevSoundNotLoaded);
       
   544 
       
   545 	iMMFDevSound->InitializeL(*this, EMMFStateTonePlaying);
       
   546 	iMMFDevSound->SetPrioritySettings(iPrioritySettings);
       
   547 
       
   548 	//[ assert the invariant ]
       
   549 	__ASSERT_ALWAYS( Invariant(), Panic(EBadStateAfterNegotiate));
       
   550 	}
       
   551 
       
   552 /**
       
   553 Set the priority settings that this controller should use to access Dev Sound
       
   554 
       
   555 @internalTechnology
       
   556 @param aPrioritySettings The requires priority settings
       
   557 */
       
   558 void CMMFAudioToneController::SetPrioritySettings(const TMMFPrioritySettings& aPrioritySettings)
       
   559 	{
       
   560 	//[ assert the invariant ]
       
   561 	__ASSERT_ALWAYS( Invariant(), Panic(EBadStateToSetPriority));
       
   562 
       
   563 	//[ assert the precondition ]
       
   564 	if(State() != EStopped)
       
   565 		{
       
   566 		ASSERT(EFalse);		// used to leave here with KErrNotReady
       
   567 		return;
       
   568 		}
       
   569 
       
   570 	//[ update the priority settings of the controller]
       
   571 	iPrioritySettings = aPrioritySettings;
       
   572 
       
   573 	if (iMMFDevSound)
       
   574 		{
       
   575 		iMMFDevSound->SetPrioritySettings(iPrioritySettings);
       
   576 		}
       
   577 
       
   578 	__ASSERT_ALWAYS( Invariant(), Panic(EBadPriorityState));
       
   579 	}
       
   580 
       
   581 
       
   582 
       
   583 /**
       
   584 This method is called by DevSound after initialization, indicating that it has completed and 
       
   585 whether there was an error
       
   586 
       
   587 @internalTechnology
       
   588 @param aError the error supplied by Dev Sound
       
   589 */
       
   590 void CMMFAudioToneController::InitializeComplete(TInt aError)
       
   591 	{
       
   592 	//[ assert the state is EPriming ]
       
   593 	__ASSERT_ALWAYS( ( State() == EPriming ), Panic( EBadState ));
       
   594 	__ASSERT_ALWAYS( iMessage, Panic( ENoMessageToProcess ));
       
   595 	
       
   596 	if(aError != KErrNone)
       
   597 		{
       
   598 		SetState( EStopped );
       
   599 		iMessage->Complete(aError);
       
   600 		}
       
   601 	else 
       
   602 		{
       
   603 		SetState( EPrimed );
       
   604 		iMessage->Complete(aError);
       
   605 		iIsResumeSupported = iMMFDevSound->IsResumeSupported();
       
   606 		}
       
   607 	
       
   608 	delete iMessage;
       
   609 	iMessage = NULL;
       
   610 	
       
   611 	// [ assert the invariant]	
       
   612 	__ASSERT_ALWAYS( Invariant(), Panic( EBadInitializeState ) );
       
   613 	}
       
   614 
       
   615 
       
   616 /**
       
   617 This method is called by DevSound after it has finished playing a tone sequence, indicating 
       
   618 whether there was an error
       
   619 
       
   620 @internalTechnology
       
   621 @param aError the error supplied by DevSound
       
   622 */
       
   623 void CMMFAudioToneController::ToneFinished(TInt aError)
       
   624 	{
       
   625 	// NB KErrInUse, KErrDied OR KErrAccessDenied may be returned 
       
   626 	// to indicate that the sound device is in use  by another higher 
       
   627 	// priority client.
       
   628 	if (aError == KErrCancel || aError == KErrInUse || 
       
   629 	    aError == KErrDied || aError == KErrAccessDenied)
       
   630 		return;
       
   631 
       
   632 	if (aError == KErrUnderflow)
       
   633 		aError = KErrNone;
       
   634 
       
   635 	if (State() != EStopped)
       
   636 		{
       
   637 		iMMFDevSound->Stop();
       
   638 		SetState( EStopped );
       
   639 		}
       
   640 
       
   641 	//now send event to client...
       
   642 	TMMFEvent event;
       
   643 	event.iEventType = KMMFEventCategoryPlaybackComplete;
       
   644 	event.iErrorCode = aError;
       
   645 	DoSendEventToClient(event);	
       
   646 	}
       
   647 
       
   648 
       
   649 
       
   650 /**
       
   651 Called my DevSound to indicate we have been thrown off H/W by a higher priority
       
   652 
       
   653 @internalTechnology
       
   654 @param aEvent contains the reason we have been contacted by DevSound
       
   655 */
       
   656 void CMMFAudioToneController::SendEventToClient(const TMMFEvent& aEvent)
       
   657 	{
       
   658 	if(State() == EPlaying)
       
   659 		SetState(EStopped);
       
   660 
       
   661 	DoSendEventToClient(aEvent);	
       
   662 	}
       
   663 
       
   664 
       
   665 
       
   666 
       
   667 /**
       
   668 Sets the playback volume
       
   669 
       
   670 @internalTechnology
       
   671 @param aVolume the required volume
       
   672 */
       
   673 void CMMFAudioToneController::MapdSetVolumeL(TInt aVolume)
       
   674 	{
       
   675 	//[ assert the invariant ]
       
   676 	__ASSERT_ALWAYS( Invariant(), Panic(EBadStateToSetVolume));
       
   677 
       
   678 	// [  precondition is true for state 
       
   679 	//    we can set the volume in any state ]
       
   680 
       
   681 	//[ precondition we have a data sink ]
       
   682 	if (!iMMFDevSound)
       
   683 		User::Leave(KErrNotReady);
       
   684 
       
   685 
       
   686 	// [ assert the precondition that aVolume is in range ]
       
   687 	TInt maxVolume = iMMFDevSound->MaxVolume();
       
   688 	if( ( aVolume < 0 ) || ( aVolume > maxVolume ))
       
   689 		User::Leave(KErrArgument);
       
   690 	
       
   691 	//[ set the volume on the device ]
       
   692 	iMMFDevSound->SetVolume(aVolume);
       
   693 
       
   694 	//[ assert the post condition volume is equal to a volume]
       
   695 	TInt soundVolume = 0;
       
   696 	soundVolume = iMMFDevSound->Volume();
       
   697 
       
   698     __ASSERT_ALWAYS( ( soundVolume == aVolume), Panic(EPostConditionViolation));
       
   699 
       
   700 	//[ assert the invariant ]
       
   701 	__ASSERT_ALWAYS( Invariant(), Panic(EBadStateAfterVolumeSet));
       
   702 	}
       
   703 
       
   704 /**
       
   705 Gets the maximum level the playback volume can be set to
       
   706 
       
   707 @internalTechnology
       
   708 @param aMaxVolume contains the maximum volume setting
       
   709 */
       
   710 void CMMFAudioToneController::MapdGetMaxVolumeL(TInt& aMaxVolume)
       
   711 	{
       
   712 	// [ assert the invariant ]
       
   713 	__ASSERT_ALWAYS( Invariant(), Panic(EBadStateToGetMaxVolume));
       
   714 
       
   715 	//[ precondition we have a data sink ]
       
   716 	if (!iMMFDevSound)
       
   717 		User::Leave(KErrNotReady);
       
   718 
       
   719 	//[ get the volume from the device ]
       
   720 	aMaxVolume = iMMFDevSound->MaxVolume();
       
   721 
       
   722 	//[ assert the invariant ]
       
   723 	__ASSERT_ALWAYS( Invariant(), Panic(EBadStateAfterGetMaxVolume));
       
   724 
       
   725 	}
       
   726 
       
   727 
       
   728 /**
       
   729 Gets the current playback volume
       
   730 
       
   731 @internalTechnology
       
   732 @param aVolume the current volume
       
   733 */
       
   734 void CMMFAudioToneController::MapdGetVolumeL(TInt& aVolume)
       
   735 	{
       
   736 	// [ assert the invariant ]
       
   737 	__ASSERT_ALWAYS( Invariant(), Panic(EBadStateToGetVolume));
       
   738 
       
   739 	//[  precondition that we have a data sink ]
       
   740 	if (!iMMFDevSound)
       
   741 		User::Leave(KErrNotReady);
       
   742 
       
   743 	aVolume = iMMFDevSound->Volume();
       
   744 	
       
   745 	// [ assert precondition that the volume is in range
       
   746 	//     0.. aMaxVolume ]
       
   747 	TInt aMaxVolume = iMMFDevSound->MaxVolume();
       
   748 	__ASSERT_ALWAYS( (aVolume <= aMaxVolume), Panic(EBadState));
       
   749 	__ASSERT_ALWAYS( (aVolume >= 0), Panic(EBadState));
       
   750 
       
   751 	// [ assert the invariant ]
       
   752 	__ASSERT_ALWAYS( Invariant(), Panic(EBadStateAfterGetVolume));
       
   753 
       
   754 	}
       
   755 
       
   756 /**
       
   757 Sets the duration over which the volume should increase
       
   758 
       
   759 @internalTechnology
       
   760 @param aRampDuration the time over which the volume should ramp
       
   761 */
       
   762 void CMMFAudioToneController::MapdSetVolumeRampL(const TTimeIntervalMicroSeconds& aRampDuration)
       
   763 	{
       
   764      // [ assert the invariant ]
       
   765 	__ASSERT_ALWAYS( Invariant(), Panic(EBadStateToSetVolumeRamp));
       
   766 
       
   767 	//[ precondition that we have a data sink ]
       
   768 	if (!iMMFDevSound)
       
   769 		User::Leave(KErrNotReady);
       
   770 
       
   771 	iMMFDevSound->SetVolumeRamp(aRampDuration);
       
   772 	
       
   773 	//[ assert the invariant ]
       
   774 	__ASSERT_ALWAYS( Invariant(), Panic(EBadStateAfterSetVolumeRamp));
       
   775 		
       
   776 	}
       
   777 
       
   778 
       
   779 /**
       
   780 Sets the balance of the tone playback
       
   781 
       
   782 @internalTechnology
       
   783 @param aBalance the required balance level (KMMFBalanceMaxLeft <= aBalance <= KMMFBalanceMaxRight)
       
   784 */
       
   785 void CMMFAudioToneController::MapdSetBalanceL(TInt aBalance)
       
   786 	{
       
   787 	//[ assert the invariant ]
       
   788 	__ASSERT_ALWAYS( Invariant(), Panic( EBadStateToSetBalance));
       
   789 
       
   790 	// [ precondition is that we have a data sink ]
       
   791 	if (!iMMFDevSound)
       
   792 		User::Leave(KErrNotReady);
       
   793 	
       
   794 	
       
   795 	// [ separate out left and right balance ]
       
   796 	TInt left  = 0;
       
   797 	TInt right = 0;
       
   798 	CalculateLeftRightBalance( left, right, aBalance );
       
   799 	
       
   800 	//[ set the balance ]
       
   801 	iMMFDevSound->SetPlayBalanceL(left, right); 
       
   802 
       
   803 	// [assert the post condition that the balance is set correctly]
       
   804 	TInt rightBalance = 0;
       
   805 	TInt leftBalance  = 0;
       
   806 	iMMFDevSound->GetPlayBalanceL(leftBalance, rightBalance); 
       
   807 
       
   808 	//[ assert post condition holds]
       
   809 	TBool postCondition = (( rightBalance == right) && ( leftBalance == left));
       
   810 	__ASSERT_ALWAYS( postCondition, Panic( EPostConditionViolation ) );
       
   811 
       
   812 	//[ assert the invariant ]
       
   813 	__ASSERT_ALWAYS( Invariant(), Panic( EBadStateAfterSetBalance));
       
   814 	}
       
   815 
       
   816 /**
       
   817 Converts the balance from a range to a left/right form.
       
   818 
       
   819 Balance is provided to devsound using left and right levels, but supplied to the controller as a range 
       
   820 (KMMFBalanceMaxLeft --> KMMFBalanceMaxRight). This method converts the range into a left/right form
       
   821 
       
   822 @internalComponent
       
   823 
       
   824 @param aLeft set to the left setting
       
   825 @param aRight set to the right setting
       
   826 @param aBalance the range required
       
   827 */
       
   828 void CMMFAudioToneController::CalculateLeftRightBalance( TInt& aLeft, TInt& aRight, TInt aBalance ) const
       
   829 	{
       
   830 	// Check the balance is within limits & modify to min or max values if necessary
       
   831 	if (aBalance < KMMFBalanceMaxLeft)
       
   832 		aBalance = KMMFBalanceMaxLeft;
       
   833 	if (aBalance > KMMFBalanceMaxRight)
       
   834 		aBalance = KMMFBalanceMaxRight;
       
   835 	
       
   836 	//[ Now separate percentage balances out from aBalance ]
       
   837 	 aLeft = (100 * (aBalance-KMMFBalanceMaxRight)) / (KMMFBalanceMaxLeft-KMMFBalanceMaxRight);
       
   838      aRight = 100 - aLeft;
       
   839 
       
   840 	 //[ assert post condition that left and right are within range ]
       
   841 	 __ASSERT_ALWAYS( ( (aLeft <= 100) && (aLeft >= 0) ), Panic(EPostConditionViolation));
       
   842 	 __ASSERT_ALWAYS( ( (aRight <= 100) && (aRight >= 0) ), Panic(EPostConditionViolation));
       
   843 	}
       
   844 
       
   845 
       
   846 /**
       
   847 Gets the balance of the tone playback
       
   848 
       
   849 @internalTechnology
       
   850 @param aBalance set to the current balance level (KMMFBalanceMaxLeft <= aBalance <= KMMFBalanceMaxRight)
       
   851 */
       
   852 void CMMFAudioToneController::MapdGetBalanceL(TInt& aBalance)
       
   853 	{
       
   854 	//[ assert the invariant ]
       
   855 	__ASSERT_ALWAYS( Invariant(), Panic(EBadStateToGetBalance));
       
   856 
       
   857 	//[ precondition that we have a sink]
       
   858 	if (!iMMFDevSound)
       
   859 		User::Leave(KErrNotReady);
       
   860 	
       
   861 	
       
   862 	TInt left = 50; // arbitrary values 
       
   863 	TInt right = 50;
       
   864 	iMMFDevSound->GetPlayBalanceL(left, right); 
       
   865 
       
   866     CalculateBalance( aBalance, left, right );
       
   867 
       
   868 	//[ assert the invariant ]
       
   869 	__ASSERT_ALWAYS( Invariant(), Panic(EBadStateAfterGetBalance));
       
   870 	}
       
   871 
       
   872 
       
   873 /**
       
   874 Converts the balance from a left/right form to a range.
       
   875 
       
   876 Balance is obtained from  DevSound using left and right levels, but supplied to the client as a range 
       
   877 (KMMFBalanceMaxLeft --> KMMFBalanceMaxRight).
       
   878 
       
   879 @internalComponent
       
   880 
       
   881 @param aLeft the current left setting
       
   882 @param aRight current right setting
       
   883 @param aBalance set to the balance range
       
   884 */
       
   885 void CMMFAudioToneController::CalculateBalance( TInt& aBalance, TInt aLeft, TInt aRight ) const
       
   886 	{
       
   887 	//[ assert pre conditions ]
       
   888 	__ASSERT_ALWAYS( (( aLeft + aRight ) == 100 ), Panic( EBadArgument ));
       
   889 	__ASSERT_ALWAYS( (( 0 <= aLeft) && ( 100 >= aLeft)), Panic( EBadArgument) );
       
   890 	__ASSERT_ALWAYS( (( 0 <= aRight) && ( 100 >= aRight)), Panic( EBadArgument) );
       
   891 
       
   892 	aBalance = (aLeft * (KMMFBalanceMaxLeft-KMMFBalanceMaxRight))/100 + KMMFBalanceMaxRight;
       
   893 
       
   894     //[ assert post condition that aBalance is within limits ]
       
   895 	__ASSERT_ALWAYS( !(aBalance < KMMFBalanceMaxLeft || aBalance > KMMFBalanceMaxRight), Panic(EBadArgument));
       
   896 	
       
   897 	}
       
   898 
       
   899 
       
   900 
       
   901 
       
   902 /**
       
   903 The function validates a state transition from iState to aState and 
       
   904 returns ETrue if the transition is allowed.
       
   905 
       
   906 @internalComponent
       
   907 @param TControllerState
       
   908 @return Valid controller state or not 
       
   909 */
       
   910 TBool CMMFAudioToneController::IsValidStateTransition( TControllerState aState ) const
       
   911 	{
       
   912 	 TBool result = ETrue ;
       
   913 	//[ assert the precondition that aState is a valid State ]
       
   914 	__ASSERT_ALWAYS( IsValidState(aState), Panic( EBadArgument ) );
       
   915 	//[ assert the invariant that iState is a valid State ]
       
   916 	__ASSERT_ALWAYS( Invariant(), Panic( EBadStateForTransition ));
       
   917 
       
   918 	// [ check the valid state transitions ]
       
   919 	  // the only invalid transition is
       
   920 	  // stopped to playing
       
   921 	if( ( iState == EStopped ) && ( aState == EPlaying ))
       
   922 		{
       
   923          result = EFalse ;
       
   924 		}
       
   925   
       
   926 	//[ assert the invariant that iState is a valid State ]
       
   927 	__ASSERT_ALWAYS( Invariant(), Panic( EBadStateAfterTransition ));
       
   928 
       
   929 	return result ;
       
   930 	}
       
   931 
       
   932 /*
       
   933 This function returns whether the invariant is valid
       
   934 
       
   935 @internalComponent
       
   936 @return Is the class in a good condition
       
   937 */
       
   938 TBool  CMMFAudioToneController::Invariant() const
       
   939 	{
       
   940 	//[ The invariant is for now defined 
       
   941 	// as simply being in the correct state
       
   942 	return IsValidState( iState);
       
   943 	}
       
   944 
       
   945 /*
       
   946 This function sets the state of the controller.
       
   947 
       
   948 @internalComponent
       
   949 @return Whether ths state transition is valid
       
   950 */
       
   951 TBool CMMFAudioToneController::SetState(TControllerState aState)
       
   952 	{
       
   953 	TBool result = ETrue;
       
   954 	//[ assert the precondition that the state is a valid state ]
       
   955    	__ASSERT_ALWAYS( IsValidState( aState),  Panic( EBadArgument ) );
       
   956 	//[ assert the invariant the current state is valid ]
       
   957 	__ASSERT_ALWAYS( Invariant(),  Panic( EStateNotValid ) );
       
   958     //[ only allow valid state transitions ]
       
   959 	if( IsValidStateTransition( aState ) )	
       
   960 		{
       
   961 		//[ valid state transition set the state]
       
   962 		iState = aState ;
       
   963 		}
       
   964 	else
       
   965 		{
       
   966 		//[ invalid state transition return EFalse ]
       
   967 		result = EFalse;         
       
   968 		}
       
   969 	// [ assert the invariant on the state ]
       
   970 	__ASSERT_ALWAYS( Invariant(), Panic( EBadState ));
       
   971 	
       
   972 	return result ;
       
   973 	}
       
   974 
       
   975 /*
       
   976 checks whether a state is valid 
       
   977 
       
   978 @internalComponent
       
   979 @return Is the state a valid one
       
   980 */
       
   981 TBool  CMMFAudioToneController::IsValidState( TControllerState aState ) const 
       
   982 	{
       
   983 	TBool result = EFalse;
       
   984      if(( aState >= EStopped ) && ( aState <= EPlaying ))
       
   985 		 {
       
   986           result = ETrue;
       
   987 		 }
       
   988 	 return result;
       
   989 	}
       
   990 
       
   991 /**
       
   992 The function State returns the current state of the audio controller
       
   993 
       
   994 @internalComponent
       
   995 @return State of the controller
       
   996 */
       
   997 CMMFAudioToneController::TControllerState CMMFAudioToneController::State() const
       
   998 	{
       
   999 	__ASSERT_ALWAYS( Invariant(), Panic( EBadState ) );
       
  1000 	return iState;
       
  1001 	}
       
  1002 
       
  1003 
       
  1004 /**
       
  1005 * MapcSetRepeatsL
       
  1006 * @param aRepeatNumberOfTimes
       
  1007 * @param aTrailingSilence
       
  1008 *
       
  1009 */
       
  1010 TInt CMMFAudioToneController::MapcSetRepeats(TInt aRepeatNumberOfTimes, const TTimeIntervalMicroSeconds& aTrailingSilence)
       
  1011 	{
       
  1012 	TInt err = KErrNone;
       
  1013 	if (!iMMFDevSound)
       
  1014 		{
       
  1015 		return KErrNotReady;
       
  1016 		}		
       
  1017 	else
       
  1018 		{
       
  1019 		if(iMMFDevSound->QueryIgnoresUnderflow())
       
  1020 			{
       
  1021 			iMMFDevSound->SetToneRepeats(aRepeatNumberOfTimes, aTrailingSilence);
       
  1022 			}
       
  1023 		else
       
  1024 			{
       
  1025 			err = KErrNotSupported;
       
  1026 			}
       
  1027 		}
       
  1028 	return err;
       
  1029 	}