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 + }