os/mm/devsound/devsoundrefplugin/src/controller/audio/MmfAudioToneController.cpp
changeset 0 bde4ae8d615e
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/os/mm/devsound/devsoundrefplugin/src/controller/audio/MmfAudioToneController.cpp	Fri Jun 15 03:10:57 2012 +0200
     1.3 @@ -0,0 +1,1029 @@
     1.4 +// Copyright (c) 2003-2009 Nokia Corporation and/or its subsidiary(-ies).
     1.5 +// All rights reserved.
     1.6 +// This component and the accompanying materials are made available
     1.7 +// under the terms of "Eclipse Public License v1.0"
     1.8 +// which accompanies this distribution, and is available
     1.9 +// at the URL "http://www.eclipse.org/legal/epl-v10.html".
    1.10 +//
    1.11 +// Initial Contributors:
    1.12 +// Nokia Corporation - initial contribution.
    1.13 +//
    1.14 +// Contributors:
    1.15 +//
    1.16 +// Description:
    1.17 +//
    1.18 +
    1.19 +
    1.20 +#include <mmf/server/mmfformat.h>
    1.21 +#include <mmf/server/mmfclip.h>
    1.22 +#include <mdaaudiosampleeditor.h>
    1.23 +#include <mmfcontrollerimplementationuids.hrh>
    1.24 +#include <mmf/common/mmffourcc.h>
    1.25 +#include <mmf/common/mmfpaniccodes.h>
    1.26 +#include "MmfAudioToneController.h"
    1.27 +#include <mmf/server/mmfaudiooutput.h>
    1.28 +
    1.29 +/*
    1.30 + A list of panic codes for the Audio Tone Controller
    1.31 +@internalTechnology
    1.32 +
    1.33 + TMmfAudioToneControllerPanics is an enumeration with the following entries:
    1.34 + EBadArgument indicates a bad argument
    1.35 + EBadState indicates a state viaolation
    1.36 + EBadInvariant indicates an invariant violation
    1.37 + EBadReset indicates failed reset
    1.38 + EPostConditionViolation indicates a post condition violation
    1.39 +*/
    1.40 +enum TMmfAudioToneControllerPanics
    1.41 +	{
    1.42 +	EBadArgument,
    1.43 +	EBadState,
    1.44 +	EBadInvariant,
    1.45 +	EBadReset,
    1.46 +	EPostConditionViolation,
    1.47 +	EBadCall,
    1.48 +	ENoDataSource,
    1.49 +	ENoDataSink,
    1.50 +	EMessageAlreadyBeingProcessed,
    1.51 +	ENoMessageToProcess,
    1.52 +	EStateNotReadyToPlay,
    1.53 +	EStateNotConstructed,
    1.54 +	EBadStateToGetDataSource,
    1.55 +	EBadStateToGetDataSink,
    1.56 +	EBadStateForPrime,
    1.57 +	EStateNotPrimed,
    1.58 +	EBadResetState,
    1.59 +	EBadStateToReset,
    1.60 +	EBadPlayState,
    1.61 +	EBadPauseState,
    1.62 +	EBadStateToPause,
    1.63 +	EBadStateToStop,
    1.64 +	EBadStopState,
    1.65 +	ENotReadyForDataSourceRemoval,
    1.66 +	EBadDataSourceRemoval,
    1.67 +	ENotReadyForDataSinkRemoval,
    1.68 +	EBadDataSinkRemoval,
    1.69 +	ENotReadyForCustomCommand,
    1.70 +	EBadStateAfterNegotiate,
    1.71 +	EBadStateToSetPriority,
    1.72 +	EBadPriorityState,
    1.73 +	EBadInitializeState,
    1.74 +	EBadStateToSetVolume,
    1.75 +	EBadStateAfterVolumeSet,
    1.76 +	EBadStateToGetMaxVolume,
    1.77 +	EBadStateAfterGetMaxVolume,
    1.78 +	EBadStateToGetVolume,
    1.79 +	EBadStateAfterGetVolume,
    1.80 +	EBadStateToSetVolumeRamp,
    1.81 +	EBadStateAfterSetVolumeRamp,
    1.82 +	EBadStateToSetBalance,
    1.83 +	EBadStateAfterSetBalance,
    1.84 +	EBadStateToGetBalance,
    1.85 +	EBadStateAfterGetBalance,
    1.86 +	EBadStateForTransition,
    1.87 +	EBadStateAfterTransition,
    1.88 +	EStateNotValid,
    1.89 +	};
    1.90 +
    1.91 +
    1.92 +/**
    1.93 + Instantiates a new Audio Tone Controller. Usually invoked from ECom
    1.94 + 
    1.95 + @internalTechnology
    1.96 + @return CMMFController* bas class for all plugin controllers
    1.97 + */
    1.98 +CMMFController* CMMFAudioToneController::NewL()
    1.99 +	{
   1.100 +	CMMFAudioToneController* self = new(ELeave) CMMFAudioToneController;
   1.101 +	CleanupStack::PushL(self);
   1.102 +	self->ConstructL();
   1.103 +	CleanupStack::Pop( self );
   1.104 +	return STATIC_CAST( CMMFController*, self );
   1.105 +	}
   1.106 +
   1.107 +
   1.108 +
   1.109 +/**
   1.110 +2nd Phase constructor
   1.111 +
   1.112 +@internalComponent
   1.113 +*/
   1.114 +void CMMFAudioToneController::ConstructL()
   1.115 +	{
   1.116 +	iSourceAndSinkAdded = EFalse;
   1.117 +
   1.118 +	// Construct custom command parsers
   1.119 +	CMMFAudioPlayDeviceCustomCommandParser* audPlayDevParser = CMMFAudioPlayDeviceCustomCommandParser::NewL(*this);
   1.120 +	CleanupStack::PushL(audPlayDevParser);
   1.121 +	AddCustomCommandParserL(*audPlayDevParser);
   1.122 +	CleanupStack::Pop( audPlayDevParser );//audPlayDevParser
   1.123 +
   1.124 +	CMMFAudioPlayControllerCustomCommandParser* audPlayConParser = CMMFAudioPlayControllerCustomCommandParser::NewL(*this);
   1.125 +	CleanupStack::PushL(audPlayConParser);
   1.126 +	AddCustomCommandParserL(*audPlayConParser);
   1.127 +	CleanupStack::Pop(audPlayConParser);//audPlayConParser
   1.128 +	
   1.129 +	CMMFAudioPlayControllerSetRepeatsCustomCommandParser* audPlayConSetRepeatsParser = CMMFAudioPlayControllerSetRepeatsCustomCommandParser::NewL(*this);
   1.130 +	CleanupStack::PushL(audPlayConSetRepeatsParser);
   1.131 +	AddCustomCommandParserL(*audPlayConSetRepeatsParser);
   1.132 +	CleanupStack::Pop(audPlayConSetRepeatsParser);
   1.133 +	
   1.134 +	// [ assert the invariant now that we are constructed ]
   1.135 +	__ASSERT_ALWAYS( Invariant(), Panic( EStateNotConstructed));
   1.136 +	}
   1.137 +
   1.138 +
   1.139 +/**
   1.140 +1st Phase constructor
   1.141 +
   1.142 +@internalComponent
   1.143 +*/
   1.144 +
   1.145 +CMMFAudioToneController::CMMFAudioToneController() : iState(EStopped)
   1.146 +	{
   1.147 +	}
   1.148 +
   1.149 +/**
   1.150 +Destructor
   1.151 +
   1.152 +@internalTechnology
   1.153 +*/
   1.154 +CMMFAudioToneController::~CMMFAudioToneController()
   1.155 +	{
   1.156 +	delete iMMFDevSound;
   1.157 +	delete iToneSequenceData;
   1.158 +	delete iMessage;
   1.159 +	}
   1.160 +
   1.161 +/**
   1.162 +Adds a data source to the controller 
   1.163 +
   1.164 +@internalTechnology
   1.165 +
   1.166 +@param aSource will provide the data the controller plays
   1.167 +*/
   1.168 +void CMMFAudioToneController::AddDataSourceL(MDataSource& aSource)
   1.169 +	{
   1.170 +	//[ assert the invariant ]
   1.171 +	__ASSERT_ALWAYS( Invariant(), Panic( EBadStateToGetDataSource));
   1.172 +
   1.173 +	// [ precondition that the controller is stopped ]
   1.174 +    if( State() != EStopped )
   1.175 +		User::Leave( KErrNotReady );
   1.176 +	
   1.177 +	//[ precondition iData source is not already configured ]
   1.178 +	if (iDataSource)
   1.179 +		User::Leave(KErrAlreadyExists);
   1.180 +
   1.181 +	//Only works with files or descriptors
   1.182 +	if ((aSource.DataSourceType() != KUidMmfFileSource ) && (aSource.DataSourceType() != KUidMmfDescriptorSource))
   1.183 +		User::Leave( KErrNotSupported ) ;
   1.184 +
   1.185 +
   1.186 +	//extract the tone data into a buffer ready to play.
   1.187 +	iToneSequenceData = CMMFDataBuffer::NewL(STATIC_CAST(CMMFClip*, &aSource)->Size());
   1.188 +
   1.189 +	aSource.SourcePrimeL();
   1.190 +	STATIC_CAST(CMMFClip*, &aSource)->ReadBufferL(iToneSequenceData,0);
   1.191 +	aSource.SourceStopL();
   1.192 +
   1.193 +
   1.194 +	//[ its now safe to set the source ]
   1.195 +	iDataSource = &aSource ;
   1.196 +
   1.197 +	//[ assert the post condition ]
   1.198 +	__ASSERT_ALWAYS(iDataSource, Panic(EMMFAudioControllerPanicDataSourceDoesNotExist));
   1.199 +
   1.200 +	iDataSource->SetSourcePrioritySettings(iPrioritySettings);
   1.201 +	}
   1.202 +
   1.203 +
   1.204 +
   1.205 +/**
   1.206 +Adds a data sink to the controller 
   1.207 +
   1.208 +@internalTechnology
   1.209 +
   1.210 +@param aSink will accept the data the controller plays
   1.211 +*/
   1.212 +void CMMFAudioToneController::AddDataSinkL(MDataSink& aSink)
   1.213 +	{
   1.214 +	//[ assert the invariant ]
   1.215 +	__ASSERT_ALWAYS( Invariant(), Panic( EBadStateToGetDataSink));
   1.216 +
   1.217 +	// [ precondition that the controller is stopped ]
   1.218 +    if( State() != EStopped )
   1.219 +		User::Leave( KErrNotReady );
   1.220 +
   1.221 +	// [ assert precondition that sink does not exist ]
   1.222 +	if (iMMFDevSound)
   1.223 +		User::Leave(KErrAlreadyExists);
   1.224 +
   1.225 +	//Only support playing to audio output 
   1.226 +	if (aSink.DataSinkType() != KUidMmfAudioOutput)
   1.227 +		User::Leave( KErrNotSupported );
   1.228 +
   1.229 +	iMMFDevSound = CMMFDevSound::NewL();
   1.230 +
   1.231 +	// [ assert post conditions that a sink has been added ]
   1.232 +	__ASSERT_ALWAYS(iMMFDevSound, Panic(EMMFAudioControllerPanicDataSinkDoesNotExist));
   1.233 +	}
   1.234 +	
   1.235 +/**
   1.236 +Primes the controller, ready for playing
   1.237 +
   1.238 +@internalTechnology
   1.239 +
   1.240 +@param aMessage allows response to client upon completion or error
   1.241 +*/
   1.242 +void CMMFAudioToneController::PrimeL(TMMFMessage& aMessage)
   1.243 +	{
   1.244 +	//[ assert the invariant ]
   1.245 +	__ASSERT_ALWAYS( Invariant(), Panic( EBadStateForPrime));
   1.246 +
   1.247 +	//[ assert the precondition ( in a friendly way for this api 
   1.248 +	// that we are either stopped or primed already ]
   1.249 +	if(!(( State() == EStopped ) || (State() == EPrimed )))
   1.250 +		User::Leave( KErrNotReady );
   1.251 +
   1.252 +	// [ precondition we have a data source & sink and aren't already processing a message]
   1.253 +	__ASSERT_ALWAYS( iDataSource, Panic( ENoDataSource));
   1.254 +	__ASSERT_ALWAYS( iMMFDevSound, Panic( ENoDataSink));
   1.255 +	__ASSERT_ALWAYS( !iMessage, Panic( EMessageAlreadyBeingProcessed ));
   1.256 +
   1.257 +	if (iState == EStopped)
   1.258 +		{
   1.259 +	
   1.260 +		iMessage = new(ELeave) TMMFMessage(aMessage); //store message
   1.261 +		__ASSERT_ALWAYS( iMessage, Panic( EPostConditionViolation )); //check if message created sucessfully
   1.262 +		SetState(EPriming);
   1.263 +
   1.264 +		TRAPD(err,NegotiateL());
   1.265 +		if(err != KErrNone)
   1.266 +			{
   1.267 +			SetState( EStopped );
   1.268 +			delete iMessage;
   1.269 +			iMessage = NULL;
   1.270 +			User::Leave(err);
   1.271 +			}
   1.272 +		}
   1.273 +	
   1.274 +	__ASSERT_ALWAYS( Invariant(), Panic( EStateNotPrimed ) );
   1.275 +
   1.276 +	}
   1.277 +
   1.278 +/**
   1.279 +Primes the controller, ready for playingAdds a data sink to the controller 
   1.280 +
   1.281 +@internalTechnology
   1.282 +*/
   1.283 +void CMMFAudioToneController::PrimeL()
   1.284 +	{
   1.285 +	Panic(EBadCall);
   1.286 +	}
   1.287 +
   1.288 +/**
   1.289 +This method resets the controller
   1.290 +
   1.291 +@internalTechnology
   1.292 +*/
   1.293 +void CMMFAudioToneController::ResetL()
   1.294 +	{
   1.295 +	__ASSERT_ALWAYS( Invariant(), Panic( EBadStateToReset ) );
   1.296 +
   1.297 +	// Stop recording if it's not stopped,
   1.298 +	if (State() != EStopped)
   1.299 +		{
   1.300 +		StopL();
   1.301 +		}
   1.302 +
   1.303 +	//[ ensure loggoff of source and sink ]
   1.304 +	iDataSource = NULL ;
   1.305 +	delete iMMFDevSound; iMMFDevSound = NULL ;
   1.306 +	iSourceAndSinkAdded = EFalse;
   1.307 +	delete iMessage;
   1.308 +	iMessage = NULL;
   1.309 +	
   1.310 +
   1.311 +	// [ assert the invariant]
   1.312 +	__ASSERT_ALWAYS( Invariant(), Panic( EBadResetState ) );
   1.313 +
   1.314 +	__ASSERT_ALWAYS( ResetPostCondition(), Panic( EBadReset ));
   1.315 +	__ASSERT_ALWAYS( Invariant(), Panic(EBadState));
   1.316 +	}
   1.317 +
   1.318 +/**
   1.319 +This function determnines if the reset post condition is valid
   1.320 +
   1.321 +@internalComponent
   1.322 +*/
   1.323 +TBool CMMFAudioToneController::ResetPostCondition() const
   1.324 +	{
   1.325 +     TBool result = EFalse ;
   1.326 +	if((iMMFDevSound == NULL)  &&
   1.327 +	(iDataSource == NULL)  && 
   1.328 +	(State() == EStopped))
   1.329 +		{
   1.330 +         result = ETrue;
   1.331 +		}
   1.332 +    return result;
   1.333 +	}
   1.334 +
   1.335 +
   1.336 +/**
   1.337 +Start playing the audio tone, passing the data to Dev Sound
   1.338 +
   1.339 +The controller will be put into the EPlaying state
   1.340 +
   1.341 +@internalTechnology
   1.342 +*/
   1.343 +void CMMFAudioToneController::PlayL()
   1.344 +	{
   1.345 +	// [ assert the precondition that the
   1.346 +	//   play command is only activated in the primed state]
   1.347 +	if ( State() != EPrimed && State() != EPausePlaying)
   1.348 +		User::Leave(KErrNotReady);
   1.349 +
   1.350 +	// [ assert the Invariant ]
   1.351 +	__ASSERT_ALWAYS( Invariant(), Panic(EStateNotReadyToPlay));
   1.352 +
   1.353 +	if(State() == EPausePlaying && iIsResumeSupported)
   1.354 +		{
   1.355 +		User::LeaveIfError(iMMFDevSound->Resume());
   1.356 +		}
   1.357 +	else
   1.358 +		{
   1.359 +		iMMFDevSound->PlayToneSequenceL(iToneSequenceData->Data());	
   1.360 +		}
   1.361 +	
   1.362 +	SetState( EPlaying );
   1.363 +	
   1.364 +	//[ assert the post condition we are playing ]
   1.365 +	__ASSERT_ALWAYS( (State() == EPlaying ), Panic( EBadState));
   1.366 +	//[ assert the invariant ]
   1.367 +	__ASSERT_ALWAYS( Invariant(), Panic(EBadPlayState));
   1.368 +	}
   1.369 +
   1.370 +/**
   1.371 +This should Pause playing of the audio tone. HOWEVER, this is not possible with a 
   1.372 +tone sequence. This method is therefore provided as a NOP purely to allow audio
   1.373 +clients to operate correctly.
   1.374 +
   1.375 +The controller will be put into the EPrimed state
   1.376 +
   1.377 +@internalTechnology
   1.378 + */
   1.379 +void CMMFAudioToneController::PauseL()
   1.380 +	{
   1.381 +	//[ assert the invariant ]
   1.382 +	__ASSERT_ALWAYS( Invariant(), Panic(EBadStateToPause));
   1.383 +
   1.384 +	__ASSERT_ALWAYS(iMMFDevSound, Panic(EMMFAudioControllerPanicDataSinkDoesNotExist));
   1.385 +
   1.386 +	if(iIsResumeSupported)
   1.387 +		{
   1.388 +		iMMFDevSound->Pause();
   1.389 +		SetState(EPausePlaying);
   1.390 +		}
   1.391 +	else
   1.392 +		{
   1.393 +		// If Resume is not supported 
   1.394 +		// this method can't do anything, as we have no interface to restart DevSound 
   1.395 +		// after pausing a tone. It need to be here however as client utility does
   1.396 +		// Pause() Stop() when stopping.
   1.397 +		SetState(EPrimed);
   1.398 +		}
   1.399 +
   1.400 +	//[ assert the post condition we are stopped ]
   1.401 +	__ASSERT_ALWAYS( (State() == EPrimed || State() == EPausePlaying), Panic( EBadState));
   1.402 +	//[ assert the invariant ]
   1.403 +	__ASSERT_ALWAYS( Invariant(), Panic(EBadPauseState));
   1.404 +	}
   1.405 +
   1.406 +/**
   1.407 +This stops the tone that is currently playing
   1.408 +The controller will be put into the EStopped state
   1.409 +
   1.410 +@internalTechnology
   1.411 +*/
   1.412 +void CMMFAudioToneController::StopL()
   1.413 +	{
   1.414 +	//[ assert the invariant ]
   1.415 +	__ASSERT_ALWAYS( Invariant(), Panic(EBadStateToStop));
   1.416 +
   1.417 +	// [ precondition that we are not already stopped 
   1.418 +	// && if we are stopped do nothing.
   1.419 +	// Due to the asynchronous nature of the controller
   1.420 +	// interaction the response to stopped when stopped 
   1.421 +	// should not be an error ]
   1.422 +	if (State() != EStopped)
   1.423 +		{
   1.424 +		//[ update state to stopped propogate to devsound ]
   1.425 +		iMMFDevSound->Stop();
   1.426 +		SetState(EStopped);
   1.427 +		}
   1.428 +
   1.429 +	//[ assert the post condition we are stopped ]
   1.430 +	__ASSERT_ALWAYS( (State() == EStopped), Panic( EBadState));
   1.431 +	//[ assert the invariant ]
   1.432 +	__ASSERT_ALWAYS( Invariant(), Panic(EBadStopState));
   1.433 +	}
   1.434 +
   1.435 +
   1.436 +/**
   1.437 +Removes a data source form the controller
   1.438 +
   1.439 +@internalTechnology
   1.440 +
   1.441 +@param aDataSource The source that is to be removed.
   1.442 +*/
   1.443 +void CMMFAudioToneController::RemoveDataSourceL(MDataSource& aDataSource )
   1.444 +	{
   1.445 +	//[ assert the invariant ]
   1.446 +	__ASSERT_ALWAYS( Invariant(), Panic(ENotReadyForDataSourceRemoval) );
   1.447 +
   1.448 +	//[ precondition is that we have a data source ]
   1.449 +	if( !iDataSource )
   1.450 +		User::Leave(KErrNotReady);
   1.451 +
   1.452 +	//[precondition the data source is the data source we have]
   1.453 +	if( iDataSource != &aDataSource )
   1.454 +		User::Leave(KErrArgument);
   1.455 +
   1.456 +	//[ the controller is in the stopped state ]
   1.457 +	if(State() != EStopped)
   1.458 +		User::Leave(KErrNotReady);
   1.459 +
   1.460 +	//[ remove the data sink from the controller and delete the format]
   1.461 +     if( iSourceAndSinkAdded )
   1.462 +		{
   1.463 +		iMMFDevSound->Stop();
   1.464 +		iSourceAndSinkAdded = EFalse ;
   1.465 +		}
   1.466 +
   1.467 +	 iDataSource = NULL ;
   1.468 +		
   1.469 +	// [ assert postcondition we are stopped ]
   1.470 +	__ASSERT_ALWAYS( (State() == EStopped), Panic(EPostConditionViolation) );
   1.471 +
   1.472 +	//[ assert postcondition the SourceAndSinkAdded is false ]
   1.473 +	__ASSERT_ALWAYS( !iSourceAndSinkAdded, Panic( EPostConditionViolation ));
   1.474 +	
   1.475 +	//[ assert postcondition the data sink  is null ]
   1.476 +	__ASSERT_ALWAYS( (iDataSource == NULL ), Panic( EPostConditionViolation ));
   1.477 +
   1.478 +	//[ assert the invariant ]
   1.479 +	__ASSERT_ALWAYS( Invariant(), Panic(EBadDataSourceRemoval));
   1.480 +	}
   1.481 +
   1.482 +
   1.483 +/**
   1.484 +Removes a data sink form the controller
   1.485 +
   1.486 +@internalTechnology
   1.487 +
   1.488 +@param aDataSink The sink that is to be removed. We donot 
   1.489 +use this value, as we only support a single sink. 
   1.490 +*/
   1.491 +void CMMFAudioToneController::RemoveDataSinkL(MDataSink& /*aDataSink*/)
   1.492 +	{
   1.493 +	//[ assert the invariant ]
   1.494 +	__ASSERT_ALWAYS( Invariant(), Panic(ENotReadyForDataSinkRemoval) );
   1.495 +
   1.496 +	//[ precondition is that we have a data sink ]
   1.497 +	if(!iMMFDevSound)
   1.498 +		User::Leave(KErrNotReady);
   1.499 +
   1.500 +	//[ the controller is in the stopped state ]
   1.501 +	if(State() != EStopped)
   1.502 +		User::Leave(KErrNotReady);
   1.503 +
   1.504 +	//[ remove the data sink from the controller and delete the format]
   1.505 +     if(iSourceAndSinkAdded)
   1.506 +		{
   1.507 +		iMMFDevSound->Stop();
   1.508 +		iSourceAndSinkAdded = EFalse;
   1.509 +		}
   1.510 +
   1.511 +	delete iMMFDevSound; iMMFDevSound = NULL;
   1.512 +
   1.513 +		
   1.514 +	// [ assert postcondition we are stopped ]
   1.515 +	__ASSERT_ALWAYS( (State() == EStopped), Panic(EPostConditionViolation) );
   1.516 +
   1.517 +	//[ assert postcondition the SourceAndSinkAdded is false ]
   1.518 +	__ASSERT_ALWAYS( !iSourceAndSinkAdded, Panic( EPostConditionViolation ));
   1.519 +	
   1.520 +	//[ assert the invariant ]
   1.521 +	__ASSERT_ALWAYS( Invariant(), Panic(EBadDataSinkRemoval));
   1.522 +	}
   1.523 +
   1.524 +/**
   1.525 +Handles a CustomCommand for the controller. This controller doesn't support Custom Commands
   1.526 +
   1.527 +@internalTechnology
   1.528 +@param aMessage
   1.529 +*/
   1.530 +void CMMFAudioToneController::CustomCommand(TMMFMessage& aMessage)
   1.531 +	{
   1.532 +	//[ assert the invariant ]
   1.533 +	__ASSERT_ALWAYS( Invariant(), Panic(ENotReadyForCustomCommand));
   1.534 +	// [ We do not have any custom commands ]
   1.535 +	aMessage.Complete(KErrNotSupported);
   1.536 +	}
   1.537 +
   1.538 +/**
   1.539 +Configures Dev Sound, ready for playing.
   1.540 +
   1.541 +@internalComponent
   1.542 +*/
   1.543 +void CMMFAudioToneController::NegotiateL()
   1.544 +	{
   1.545 +	if (!iMMFDevSound)
   1.546 +		Panic(EMMFAudioOutputDevSoundNotLoaded);
   1.547 +
   1.548 +	iMMFDevSound->InitializeL(*this, EMMFStateTonePlaying);
   1.549 +	iMMFDevSound->SetPrioritySettings(iPrioritySettings);
   1.550 +
   1.551 +	//[ assert the invariant ]
   1.552 +	__ASSERT_ALWAYS( Invariant(), Panic(EBadStateAfterNegotiate));
   1.553 +	}
   1.554 +
   1.555 +/**
   1.556 +Set the priority settings that this controller should use to access Dev Sound
   1.557 +
   1.558 +@internalTechnology
   1.559 +@param aPrioritySettings The requires priority settings
   1.560 +*/
   1.561 +void CMMFAudioToneController::SetPrioritySettings(const TMMFPrioritySettings& aPrioritySettings)
   1.562 +	{
   1.563 +	//[ assert the invariant ]
   1.564 +	__ASSERT_ALWAYS( Invariant(), Panic(EBadStateToSetPriority));
   1.565 +
   1.566 +	//[ assert the precondition ]
   1.567 +	if(State() != EStopped)
   1.568 +		{
   1.569 +		ASSERT(EFalse);		// used to leave here with KErrNotReady
   1.570 +		return;
   1.571 +		}
   1.572 +
   1.573 +	//[ update the priority settings of the controller]
   1.574 +	iPrioritySettings = aPrioritySettings;
   1.575 +
   1.576 +	if (iMMFDevSound)
   1.577 +		{
   1.578 +		iMMFDevSound->SetPrioritySettings(iPrioritySettings);
   1.579 +		}
   1.580 +
   1.581 +	__ASSERT_ALWAYS( Invariant(), Panic(EBadPriorityState));
   1.582 +	}
   1.583 +
   1.584 +
   1.585 +
   1.586 +/**
   1.587 +This method is called by DevSound after initialization, indicating that it has completed and 
   1.588 +whether there was an error
   1.589 +
   1.590 +@internalTechnology
   1.591 +@param aError the error supplied by Dev Sound
   1.592 +*/
   1.593 +void CMMFAudioToneController::InitializeComplete(TInt aError)
   1.594 +	{
   1.595 +	//[ assert the state is EPriming ]
   1.596 +	__ASSERT_ALWAYS( ( State() == EPriming ), Panic( EBadState ));
   1.597 +	__ASSERT_ALWAYS( iMessage, Panic( ENoMessageToProcess ));
   1.598 +	
   1.599 +	if(aError != KErrNone)
   1.600 +		{
   1.601 +		SetState( EStopped );
   1.602 +		iMessage->Complete(aError);
   1.603 +		}
   1.604 +	else 
   1.605 +		{
   1.606 +		SetState( EPrimed );
   1.607 +		iMessage->Complete(aError);
   1.608 +		iIsResumeSupported = iMMFDevSound->IsResumeSupported();
   1.609 +		}
   1.610 +	
   1.611 +	delete iMessage;
   1.612 +	iMessage = NULL;
   1.613 +	
   1.614 +	// [ assert the invariant]	
   1.615 +	__ASSERT_ALWAYS( Invariant(), Panic( EBadInitializeState ) );
   1.616 +	}
   1.617 +
   1.618 +
   1.619 +/**
   1.620 +This method is called by DevSound after it has finished playing a tone sequence, indicating 
   1.621 +whether there was an error
   1.622 +
   1.623 +@internalTechnology
   1.624 +@param aError the error supplied by DevSound
   1.625 +*/
   1.626 +void CMMFAudioToneController::ToneFinished(TInt aError)
   1.627 +	{
   1.628 +	// NB KErrInUse, KErrDied OR KErrAccessDenied may be returned 
   1.629 +	// to indicate that the sound device is in use  by another higher 
   1.630 +	// priority client.
   1.631 +	if (aError == KErrCancel || aError == KErrInUse || 
   1.632 +	    aError == KErrDied || aError == KErrAccessDenied)
   1.633 +		return;
   1.634 +
   1.635 +	if (aError == KErrUnderflow)
   1.636 +		aError = KErrNone;
   1.637 +
   1.638 +	if (State() != EStopped)
   1.639 +		{
   1.640 +		iMMFDevSound->Stop();
   1.641 +		SetState( EStopped );
   1.642 +		}
   1.643 +
   1.644 +	//now send event to client...
   1.645 +	TMMFEvent event;
   1.646 +	event.iEventType = KMMFEventCategoryPlaybackComplete;
   1.647 +	event.iErrorCode = aError;
   1.648 +	DoSendEventToClient(event);	
   1.649 +	}
   1.650 +
   1.651 +
   1.652 +
   1.653 +/**
   1.654 +Called my DevSound to indicate we have been thrown off H/W by a higher priority
   1.655 +
   1.656 +@internalTechnology
   1.657 +@param aEvent contains the reason we have been contacted by DevSound
   1.658 +*/
   1.659 +void CMMFAudioToneController::SendEventToClient(const TMMFEvent& aEvent)
   1.660 +	{
   1.661 +	if(State() == EPlaying)
   1.662 +		SetState(EStopped);
   1.663 +
   1.664 +	DoSendEventToClient(aEvent);	
   1.665 +	}
   1.666 +
   1.667 +
   1.668 +
   1.669 +
   1.670 +/**
   1.671 +Sets the playback volume
   1.672 +
   1.673 +@internalTechnology
   1.674 +@param aVolume the required volume
   1.675 +*/
   1.676 +void CMMFAudioToneController::MapdSetVolumeL(TInt aVolume)
   1.677 +	{
   1.678 +	//[ assert the invariant ]
   1.679 +	__ASSERT_ALWAYS( Invariant(), Panic(EBadStateToSetVolume));
   1.680 +
   1.681 +	// [  precondition is true for state 
   1.682 +	//    we can set the volume in any state ]
   1.683 +
   1.684 +	//[ precondition we have a data sink ]
   1.685 +	if (!iMMFDevSound)
   1.686 +		User::Leave(KErrNotReady);
   1.687 +
   1.688 +
   1.689 +	// [ assert the precondition that aVolume is in range ]
   1.690 +	TInt maxVolume = iMMFDevSound->MaxVolume();
   1.691 +	if( ( aVolume < 0 ) || ( aVolume > maxVolume ))
   1.692 +		User::Leave(KErrArgument);
   1.693 +	
   1.694 +	//[ set the volume on the device ]
   1.695 +	iMMFDevSound->SetVolume(aVolume);
   1.696 +
   1.697 +	//[ assert the post condition volume is equal to a volume]
   1.698 +	TInt soundVolume = 0;
   1.699 +	soundVolume = iMMFDevSound->Volume();
   1.700 +
   1.701 +    __ASSERT_ALWAYS( ( soundVolume == aVolume), Panic(EPostConditionViolation));
   1.702 +
   1.703 +	//[ assert the invariant ]
   1.704 +	__ASSERT_ALWAYS( Invariant(), Panic(EBadStateAfterVolumeSet));
   1.705 +	}
   1.706 +
   1.707 +/**
   1.708 +Gets the maximum level the playback volume can be set to
   1.709 +
   1.710 +@internalTechnology
   1.711 +@param aMaxVolume contains the maximum volume setting
   1.712 +*/
   1.713 +void CMMFAudioToneController::MapdGetMaxVolumeL(TInt& aMaxVolume)
   1.714 +	{
   1.715 +	// [ assert the invariant ]
   1.716 +	__ASSERT_ALWAYS( Invariant(), Panic(EBadStateToGetMaxVolume));
   1.717 +
   1.718 +	//[ precondition we have a data sink ]
   1.719 +	if (!iMMFDevSound)
   1.720 +		User::Leave(KErrNotReady);
   1.721 +
   1.722 +	//[ get the volume from the device ]
   1.723 +	aMaxVolume = iMMFDevSound->MaxVolume();
   1.724 +
   1.725 +	//[ assert the invariant ]
   1.726 +	__ASSERT_ALWAYS( Invariant(), Panic(EBadStateAfterGetMaxVolume));
   1.727 +
   1.728 +	}
   1.729 +
   1.730 +
   1.731 +/**
   1.732 +Gets the current playback volume
   1.733 +
   1.734 +@internalTechnology
   1.735 +@param aVolume the current volume
   1.736 +*/
   1.737 +void CMMFAudioToneController::MapdGetVolumeL(TInt& aVolume)
   1.738 +	{
   1.739 +	// [ assert the invariant ]
   1.740 +	__ASSERT_ALWAYS( Invariant(), Panic(EBadStateToGetVolume));
   1.741 +
   1.742 +	//[  precondition that we have a data sink ]
   1.743 +	if (!iMMFDevSound)
   1.744 +		User::Leave(KErrNotReady);
   1.745 +
   1.746 +	aVolume = iMMFDevSound->Volume();
   1.747 +	
   1.748 +	// [ assert precondition that the volume is in range
   1.749 +	//     0.. aMaxVolume ]
   1.750 +	TInt aMaxVolume = iMMFDevSound->MaxVolume();
   1.751 +	__ASSERT_ALWAYS( (aVolume <= aMaxVolume), Panic(EBadState));
   1.752 +	__ASSERT_ALWAYS( (aVolume >= 0), Panic(EBadState));
   1.753 +
   1.754 +	// [ assert the invariant ]
   1.755 +	__ASSERT_ALWAYS( Invariant(), Panic(EBadStateAfterGetVolume));
   1.756 +
   1.757 +	}
   1.758 +
   1.759 +/**
   1.760 +Sets the duration over which the volume should increase
   1.761 +
   1.762 +@internalTechnology
   1.763 +@param aRampDuration the time over which the volume should ramp
   1.764 +*/
   1.765 +void CMMFAudioToneController::MapdSetVolumeRampL(const TTimeIntervalMicroSeconds& aRampDuration)
   1.766 +	{
   1.767 +     // [ assert the invariant ]
   1.768 +	__ASSERT_ALWAYS( Invariant(), Panic(EBadStateToSetVolumeRamp));
   1.769 +
   1.770 +	//[ precondition that we have a data sink ]
   1.771 +	if (!iMMFDevSound)
   1.772 +		User::Leave(KErrNotReady);
   1.773 +
   1.774 +	iMMFDevSound->SetVolumeRamp(aRampDuration);
   1.775 +	
   1.776 +	//[ assert the invariant ]
   1.777 +	__ASSERT_ALWAYS( Invariant(), Panic(EBadStateAfterSetVolumeRamp));
   1.778 +		
   1.779 +	}
   1.780 +
   1.781 +
   1.782 +/**
   1.783 +Sets the balance of the tone playback
   1.784 +
   1.785 +@internalTechnology
   1.786 +@param aBalance the required balance level (KMMFBalanceMaxLeft <= aBalance <= KMMFBalanceMaxRight)
   1.787 +*/
   1.788 +void CMMFAudioToneController::MapdSetBalanceL(TInt aBalance)
   1.789 +	{
   1.790 +	//[ assert the invariant ]
   1.791 +	__ASSERT_ALWAYS( Invariant(), Panic( EBadStateToSetBalance));
   1.792 +
   1.793 +	// [ precondition is that we have a data sink ]
   1.794 +	if (!iMMFDevSound)
   1.795 +		User::Leave(KErrNotReady);
   1.796 +	
   1.797 +	
   1.798 +	// [ separate out left and right balance ]
   1.799 +	TInt left  = 0;
   1.800 +	TInt right = 0;
   1.801 +	CalculateLeftRightBalance( left, right, aBalance );
   1.802 +	
   1.803 +	//[ set the balance ]
   1.804 +	iMMFDevSound->SetPlayBalanceL(left, right); 
   1.805 +
   1.806 +	// [assert the post condition that the balance is set correctly]
   1.807 +	TInt rightBalance = 0;
   1.808 +	TInt leftBalance  = 0;
   1.809 +	iMMFDevSound->GetPlayBalanceL(leftBalance, rightBalance); 
   1.810 +
   1.811 +	//[ assert post condition holds]
   1.812 +	TBool postCondition = (( rightBalance == right) && ( leftBalance == left));
   1.813 +	__ASSERT_ALWAYS( postCondition, Panic( EPostConditionViolation ) );
   1.814 +
   1.815 +	//[ assert the invariant ]
   1.816 +	__ASSERT_ALWAYS( Invariant(), Panic( EBadStateAfterSetBalance));
   1.817 +	}
   1.818 +
   1.819 +/**
   1.820 +Converts the balance from a range to a left/right form.
   1.821 +
   1.822 +Balance is provided to devsound using left and right levels, but supplied to the controller as a range 
   1.823 +(KMMFBalanceMaxLeft --> KMMFBalanceMaxRight). This method converts the range into a left/right form
   1.824 +
   1.825 +@internalComponent
   1.826 +
   1.827 +@param aLeft set to the left setting
   1.828 +@param aRight set to the right setting
   1.829 +@param aBalance the range required
   1.830 +*/
   1.831 +void CMMFAudioToneController::CalculateLeftRightBalance( TInt& aLeft, TInt& aRight, TInt aBalance ) const
   1.832 +	{
   1.833 +	// Check the balance is within limits & modify to min or max values if necessary
   1.834 +	if (aBalance < KMMFBalanceMaxLeft)
   1.835 +		aBalance = KMMFBalanceMaxLeft;
   1.836 +	if (aBalance > KMMFBalanceMaxRight)
   1.837 +		aBalance = KMMFBalanceMaxRight;
   1.838 +	
   1.839 +	//[ Now separate percentage balances out from aBalance ]
   1.840 +	 aLeft = (100 * (aBalance-KMMFBalanceMaxRight)) / (KMMFBalanceMaxLeft-KMMFBalanceMaxRight);
   1.841 +     aRight = 100 - aLeft;
   1.842 +
   1.843 +	 //[ assert post condition that left and right are within range ]
   1.844 +	 __ASSERT_ALWAYS( ( (aLeft <= 100) && (aLeft >= 0) ), Panic(EPostConditionViolation));
   1.845 +	 __ASSERT_ALWAYS( ( (aRight <= 100) && (aRight >= 0) ), Panic(EPostConditionViolation));
   1.846 +	}
   1.847 +
   1.848 +
   1.849 +/**
   1.850 +Gets the balance of the tone playback
   1.851 +
   1.852 +@internalTechnology
   1.853 +@param aBalance set to the current balance level (KMMFBalanceMaxLeft <= aBalance <= KMMFBalanceMaxRight)
   1.854 +*/
   1.855 +void CMMFAudioToneController::MapdGetBalanceL(TInt& aBalance)
   1.856 +	{
   1.857 +	//[ assert the invariant ]
   1.858 +	__ASSERT_ALWAYS( Invariant(), Panic(EBadStateToGetBalance));
   1.859 +
   1.860 +	//[ precondition that we have a sink]
   1.861 +	if (!iMMFDevSound)
   1.862 +		User::Leave(KErrNotReady);
   1.863 +	
   1.864 +	
   1.865 +	TInt left = 50; // arbitrary values 
   1.866 +	TInt right = 50;
   1.867 +	iMMFDevSound->GetPlayBalanceL(left, right); 
   1.868 +
   1.869 +    CalculateBalance( aBalance, left, right );
   1.870 +
   1.871 +	//[ assert the invariant ]
   1.872 +	__ASSERT_ALWAYS( Invariant(), Panic(EBadStateAfterGetBalance));
   1.873 +	}
   1.874 +
   1.875 +
   1.876 +/**
   1.877 +Converts the balance from a left/right form to a range.
   1.878 +
   1.879 +Balance is obtained from  DevSound using left and right levels, but supplied to the client as a range 
   1.880 +(KMMFBalanceMaxLeft --> KMMFBalanceMaxRight).
   1.881 +
   1.882 +@internalComponent
   1.883 +
   1.884 +@param aLeft the current left setting
   1.885 +@param aRight current right setting
   1.886 +@param aBalance set to the balance range
   1.887 +*/
   1.888 +void CMMFAudioToneController::CalculateBalance( TInt& aBalance, TInt aLeft, TInt aRight ) const
   1.889 +	{
   1.890 +	//[ assert pre conditions ]
   1.891 +	__ASSERT_ALWAYS( (( aLeft + aRight ) == 100 ), Panic( EBadArgument ));
   1.892 +	__ASSERT_ALWAYS( (( 0 <= aLeft) && ( 100 >= aLeft)), Panic( EBadArgument) );
   1.893 +	__ASSERT_ALWAYS( (( 0 <= aRight) && ( 100 >= aRight)), Panic( EBadArgument) );
   1.894 +
   1.895 +	aBalance = (aLeft * (KMMFBalanceMaxLeft-KMMFBalanceMaxRight))/100 + KMMFBalanceMaxRight;
   1.896 +
   1.897 +    //[ assert post condition that aBalance is within limits ]
   1.898 +	__ASSERT_ALWAYS( !(aBalance < KMMFBalanceMaxLeft || aBalance > KMMFBalanceMaxRight), Panic(EBadArgument));
   1.899 +	
   1.900 +	}
   1.901 +
   1.902 +
   1.903 +
   1.904 +
   1.905 +/**
   1.906 +The function validates a state transition from iState to aState and 
   1.907 +returns ETrue if the transition is allowed.
   1.908 +
   1.909 +@internalComponent
   1.910 +@param TControllerState
   1.911 +@return Valid controller state or not 
   1.912 +*/
   1.913 +TBool CMMFAudioToneController::IsValidStateTransition( TControllerState aState ) const
   1.914 +	{
   1.915 +	 TBool result = ETrue ;
   1.916 +	//[ assert the precondition that aState is a valid State ]
   1.917 +	__ASSERT_ALWAYS( IsValidState(aState), Panic( EBadArgument ) );
   1.918 +	//[ assert the invariant that iState is a valid State ]
   1.919 +	__ASSERT_ALWAYS( Invariant(), Panic( EBadStateForTransition ));
   1.920 +
   1.921 +	// [ check the valid state transitions ]
   1.922 +	  // the only invalid transition is
   1.923 +	  // stopped to playing
   1.924 +	if( ( iState == EStopped ) && ( aState == EPlaying ))
   1.925 +		{
   1.926 +         result = EFalse ;
   1.927 +		}
   1.928 +  
   1.929 +	//[ assert the invariant that iState is a valid State ]
   1.930 +	__ASSERT_ALWAYS( Invariant(), Panic( EBadStateAfterTransition ));
   1.931 +
   1.932 +	return result ;
   1.933 +	}
   1.934 +
   1.935 +/*
   1.936 +This function returns whether the invariant is valid
   1.937 +
   1.938 +@internalComponent
   1.939 +@return Is the class in a good condition
   1.940 +*/
   1.941 +TBool  CMMFAudioToneController::Invariant() const
   1.942 +	{
   1.943 +	//[ The invariant is for now defined 
   1.944 +	// as simply being in the correct state
   1.945 +	return IsValidState( iState);
   1.946 +	}
   1.947 +
   1.948 +/*
   1.949 +This function sets the state of the controller.
   1.950 +
   1.951 +@internalComponent
   1.952 +@return Whether ths state transition is valid
   1.953 +*/
   1.954 +TBool CMMFAudioToneController::SetState(TControllerState aState)
   1.955 +	{
   1.956 +	TBool result = ETrue;
   1.957 +	//[ assert the precondition that the state is a valid state ]
   1.958 +   	__ASSERT_ALWAYS( IsValidState( aState),  Panic( EBadArgument ) );
   1.959 +	//[ assert the invariant the current state is valid ]
   1.960 +	__ASSERT_ALWAYS( Invariant(),  Panic( EStateNotValid ) );
   1.961 +    //[ only allow valid state transitions ]
   1.962 +	if( IsValidStateTransition( aState ) )	
   1.963 +		{
   1.964 +		//[ valid state transition set the state]
   1.965 +		iState = aState ;
   1.966 +		}
   1.967 +	else
   1.968 +		{
   1.969 +		//[ invalid state transition return EFalse ]
   1.970 +		result = EFalse;         
   1.971 +		}
   1.972 +	// [ assert the invariant on the state ]
   1.973 +	__ASSERT_ALWAYS( Invariant(), Panic( EBadState ));
   1.974 +	
   1.975 +	return result ;
   1.976 +	}
   1.977 +
   1.978 +/*
   1.979 +checks whether a state is valid 
   1.980 +
   1.981 +@internalComponent
   1.982 +@return Is the state a valid one
   1.983 +*/
   1.984 +TBool  CMMFAudioToneController::IsValidState( TControllerState aState ) const 
   1.985 +	{
   1.986 +	TBool result = EFalse;
   1.987 +     if(( aState >= EStopped ) && ( aState <= EPlaying ))
   1.988 +		 {
   1.989 +          result = ETrue;
   1.990 +		 }
   1.991 +	 return result;
   1.992 +	}
   1.993 +
   1.994 +/**
   1.995 +The function State returns the current state of the audio controller
   1.996 +
   1.997 +@internalComponent
   1.998 +@return State of the controller
   1.999 +*/
  1.1000 +CMMFAudioToneController::TControllerState CMMFAudioToneController::State() const
  1.1001 +	{
  1.1002 +	__ASSERT_ALWAYS( Invariant(), Panic( EBadState ) );
  1.1003 +	return iState;
  1.1004 +	}
  1.1005 +
  1.1006 +
  1.1007 +/**
  1.1008 +* MapcSetRepeatsL
  1.1009 +* @param aRepeatNumberOfTimes
  1.1010 +* @param aTrailingSilence
  1.1011 +*
  1.1012 +*/
  1.1013 +TInt CMMFAudioToneController::MapcSetRepeats(TInt aRepeatNumberOfTimes, const TTimeIntervalMicroSeconds& aTrailingSilence)
  1.1014 +	{
  1.1015 +	TInt err = KErrNone;
  1.1016 +	if (!iMMFDevSound)
  1.1017 +		{
  1.1018 +		return KErrNotReady;
  1.1019 +		}		
  1.1020 +	else
  1.1021 +		{
  1.1022 +		if(iMMFDevSound->QueryIgnoresUnderflow())
  1.1023 +			{
  1.1024 +			iMMFDevSound->SetToneRepeats(aRepeatNumberOfTimes, aTrailingSilence);
  1.1025 +			}
  1.1026 +		else
  1.1027 +			{
  1.1028 +			err = KErrNotSupported;
  1.1029 +			}
  1.1030 +		}
  1.1031 +	return err;
  1.1032 +	}