os/mm/devsound/devsoundrefplugin/src/controller/audio/MmfAudioToneController.cpp
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
     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 	}