diff -r 000000000000 -r 40261b775718 mmlibs/mmfw/src/Plugin/Controller/Audio/MmfAudioController.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mmlibs/mmfw/src/Plugin/Controller/Audio/MmfAudioController.cpp Tue Feb 02 01:56:55 2010 +0200 @@ -0,0 +1,3094 @@ +// Copyright (c) 2002-2009 Nokia Corporation and/or its subsidiary(-ies). +// All rights reserved. +// This component and the accompanying materials are made available +// under the terms of "Eclipse Public License v1.0" +// which accompanies this distribution, and is available +// at the URL "http://www.eclipse.org/legal/epl-v10.html". +// +// Initial Contributors: +// Nokia Corporation - initial contribution. +// +// Contributors: +// +// Description: +// + + +#include +#include +#include +#include +#include +#include +#include "MmfAudioController.h" +#include +#include +#include +#include + +const TUint KSampleRate8000Hz = 8000; +const TUint KSampleRate11025Hz = 11025; +const TUint KSampleRate12000Hz = 12000; +const TUint KSampleRate16000Hz = 16000; +const TUint KSampleRate22050Hz = 22050; +const TUint KSampleRate24000Hz = 24000; +const TUint KSampleRate32000Hz = 32000; +const TUint KSampleRate44100Hz = 44100; +const TUint KSampleRate48000Hz = 48000; +const TUint KSampleRate64000Hz = 64000; +const TUint KSampleRate88200Hz = 88200; +const TUint KSampleRate96000Hz = 96000; +const TUint KNumChannelsMono = 1; +const TUint KNumChannelsStereo = 2; + +/* + TMmfAudioControllerPanics is an enumeration with the following entries: + EBadArgument indicates a bad argument + EBadState indicates a state viaolation + EBadInvariant indicates an invariant violation + EBadReset indicates failed reset + EPostConditionViolation indicates a post condition violation +*/ +enum TMmfAudioControllerPanics + { + EBadArgument, + EBadState, + EBadInvariant, + EBadReset, + EPostConditionViolation, + EStateNotConstructed, + EBadStateToGetDataSource, + ENoAudioInput, + EBadStateToGetDataSink, + ENoAudioOutput, + EBadStateForPrime, + ENoDataSource, + ENoDataSink, + EStateNotPrimed, + EBadResetState, + EBadStateToReset, + EStateNotReadyToPlay, + EBadPlayState, + EBadPauseState, + EBadStateToPause, + EBadStateToStop, + EBadStopState, + EBadStateToPosition, + EBadStatePosition, + EBadStateToSetPosition, + EBadStateSetPosition, + EBadStateToDuration, + EBadStateDuration, + EBadStateToGetNumberOfMetaDataEntries, + EBadStateGetNumberOfMetaDataEntries, + EBadStateToGetMetaDataEntries, + EBadStateGetMetaDataEntries, + EMetaEntryIsNull, + ENotReadyForDataSourceRemoval, + EBadDataSourceRemoval, + ENotReadyForDataSinkRemoval, + EBadDataSinkRemoval, + ENotReadyForCustomCommand, + EBadStateAfterNegotiate, + EBadStateToNegotiate, + EBadStateToSetPriority, + EBadPriorityState, + EBadStateToSendEventToClient, + EBadStateAfterSendEventToClient, + EBadStateToSetVolume, + EBadStateAfterVolumeSet, + EBadStateToGetMaxVolume, + EBadStateAfterGetMaxVolume, + EBadStateToGetVolume, + EBadStateAfterGetVolume, + EBadStateToSetVolumeRamp, + EBadStateAfterSetVolumeRamp, + EBadStateToSetBalance, + EBadStateAfterSetBalance, + EBadStateToGetBalance, + EBadStateAfterGetBalance, + EBadStateToSetGain, + EBadStateAfterGainSet, + EBadStateToGetMaxGain, + EBadStateAfterGetMaxGain, + EBadStateToGetGain, + EBadStateAfterGetGain, + EBadStateToGetRecordTimeAvailable, + EBadStateAfterGetRecordTimeAvailable, + ENoMemoryToRecord, + EBadStateToGetMaxFileSize, + EBadStateAfterGetMaxFileSize, + EBadStateToCrop, + EBadStateAfterCrop, + EBadStateToAddMetaDataEntry, + EBadStateAfterAddMetaDataEntry, + EBadStateToRemoveMetaDataEntry, + EBadStateAfterRemoveMetaDataEntry, + EBadStateToReplaceMetaDataEntry, + EBadStateAfterReplaceMetaDataEntry, + EBadStateToSetSourceSampleRate, + EBadStateAfterSetSourceSampleRate, + EBadStateToSetSourceNumChannels, + EBadStateAfterSetSourceNumChannels, + EBadStateToSetSourceFormat, + EBadStateAfterSetSourceFormat, + EBadStateToSetSinkSampleRate, + EBadStateAfterSetSinkSampleRate, + EBadStateToSetSinkNumChannels, + EBadStateAfterSetSinkNumChannels, + EBadStateToSetSinkFormat, + EBadStateAfterSetSinkFormat, + EBadStateToSetCodec, + EBadStateAfterSetCodec, + EBadStateToSetSourceBitRate, + EBadStateAfterSetSourceBitRate, + EBadStateToSetSinkBitRate, + EBadStateAfterSetSinkBitRate, + ESetRateIsNotSameAsBitRate, + EBadStateToGetSourceSampleRate, + EBadStateAfterGetSourceSampleRate, + EBadStateToGetSourceBitRate, + EBadStateAfterGetSourceBitRate, + EBadStateToGetSourceNumChannels, + EBadStateAfterGetSourceNumChannels, + EBadStateToGetSourceFormat, + EBadStateAfterGetSourceFormat, + EInvalidState, + EBadStateToRegisterAsClient, + EBadStateAfterRegisterAsClient, + EBadStateToCancelRegisterAsClient, + EBadStateAfterCancelRegisterAsClient, + EBadStateToGetResourceNotificationData, + EBadStateAfterGetResourceNotificationData, + EBadStateToResumePlay, + EBadStateAfterResumePlay, + }; + +/** +This method generates a panic + +@param aPanicCode +*/ +void Panic(TInt aPanicCode) + { + _LIT(KMMFAudioControllerPanicCategory, "MMFAudioController"); + User::Panic(KMMFAudioControllerPanicCategory, aPanicCode); + } + +/** + * Static NewL + * + * @return CMMFAudioController* + */ +CMMFController* CMMFAudioController::NewL() + { + CMMFAudioController* self = new(ELeave) CMMFAudioController; + CleanupStack::PushL(self); + self->ConstructL(); + CleanupStack::Pop( self ); + return STATIC_CAST( CMMFController*, self ); + } + +/** +* ConstructL +* +*/ +void CMMFAudioController::ConstructL() + { + iDataSource = NULL; + iDataSink = NULL; + iDataPath = CMMFDataPath2::NewL(iMediaId, *this); + iSourceFormat = NULL; + iSinkFormat = NULL; + iSourceAndSinkAdded = EFalse; + iStoppingRecording = EFalse; + + + //iMediaId has already been set up + SetState( EStopped ); + //iPrioritySettings not initialised because they are held by the controller framework + + // Construct custom command parsers + CMMFAudioPlayDeviceCustomCommandParser* audPlayDevParser = CMMFAudioPlayDeviceCustomCommandParser::NewL(*this); + CleanupStack::PushL(audPlayDevParser); + AddCustomCommandParserL(*audPlayDevParser); + CleanupStack::Pop( audPlayDevParser ); + + CMMFAudioRecordDeviceCustomCommandParser* audRecDevParser = CMMFAudioRecordDeviceCustomCommandParser::NewL(*this); + CleanupStack::PushL(audRecDevParser); + AddCustomCommandParserL(*audRecDevParser); + CleanupStack::Pop(audRecDevParser); + + CMMFAudioPlayControllerCustomCommandParser* audPlayConParser = CMMFAudioPlayControllerCustomCommandParser::NewL(*this); + CleanupStack::PushL(audPlayConParser); + AddCustomCommandParserL(*audPlayConParser); + CleanupStack::Pop(audPlayConParser); + + CMMFAudioRecordControllerCustomCommandParser* audRecConParser = CMMFAudioRecordControllerCustomCommandParser::NewL(*this); + CleanupStack::PushL(audRecConParser); + AddCustomCommandParserL(*audRecConParser); + CleanupStack::Pop(audRecConParser); + + CMMFAudioControllerCustomCommandParser* audConParser = CMMFAudioControllerCustomCommandParser::NewL(*this); + CleanupStack::PushL(audConParser); + AddCustomCommandParserL(*audConParser); + CleanupStack::Pop(audConParser); + + CMMFDRMCustomCommandParser* drmParser = CMMFDRMCustomCommandParser::NewL(*this); + CleanupStack::PushL(drmParser); + AddCustomCommandParserL(*drmParser); + CleanupStack::Pop(drmParser); + + CMMFResourceNotificationCustomCommandParser* NotiParser = CMMFResourceNotificationCustomCommandParser::NewL(*this); + CleanupStack::PushL(NotiParser); + AddCustomCommandParserL(*NotiParser); + CleanupStack::Pop(NotiParser);//audio resource Notification Parser + + CMMFAudioPlayControllerSetRepeatsCustomCommandParser* audPlayConSetRepeatsParser = CMMFAudioPlayControllerSetRepeatsCustomCommandParser::NewL(*this); + CleanupStack::PushL(audPlayConSetRepeatsParser); + AddCustomCommandParserL(*audPlayConSetRepeatsParser); + CleanupStack::Pop(audPlayConSetRepeatsParser); + + + // [ assert the invariant now that we are constructed ] + __ASSERT_ALWAYS( Invariant(), Panic( EStateNotConstructed)); + } + +/** +* +* CMMFAudioController +* +*/ + +CMMFAudioController::CMMFAudioController() + : iMediaId(KUidMediaTypeAudio), + iDisableAutoIntent(EFalse), + iState(EStopped) + { + } + +/** +* +* ~CMMFAudioController +* +*/ + +CMMFAudioController::~CMMFAudioController() + { + // [ ensure we have logged off the thread ] + if( iDataPath ) + { + iDataPath->ResetL(); // this does not leave + } + delete iDataPath; + delete iSourceFormat; + delete iSinkFormat; + delete iStoppingMessage; + } + +/** + * AddDataSourceL + * + * Adds a data source to the controller + * + * @param aSource + * Preconditions: + * We are stopped + * Source does not already exist + * Postconditions: + * iDataSource != NULL + * iDataSourceAdded == ETrue + */ +void CMMFAudioController::AddDataSourceL(MDataSource& aSource) + { + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic( EBadStateToGetDataSource)); + + // [ precondition that the controller is stopped ] + if( State() != EStopped ) + User::Leave( KErrNotReady ); + + //[ precondition iData source is not already configured ] + if (iDataSource) + User::Leave(KErrAlreadyExists); + + // Note that this code is not generic for sources + // It it only checks for file, des clips and audio inputs + // If a new source type eg a Url Clip then this needs to be added to the supported source Uids + if ( SourceFormatRequired( aSource) ) + { + // Get the format from the Source if possible from no specific supplier + TRAPD(err, iSourceFormat = CMMFFormatDecode::NewL(&aSource, KNullDesC, iSourceFormatSupportsCustomInterfaces)); + //[ we want to complete silently for KErrNotSupported + // because there is a possibility that the client + // wants to add the data format later, see audio api for + // a description of this feature] + if ((err != KErrNotSupported) && (err != KErrNone)) + { + User::Leave(err); + } + } + else if (aSource.DataSourceType()==KUidMmfAudioInput) + { + //[ ensure that the audio input has a pointer to dev sound ] + CMMFAudioInput* audioInput = STATIC_CAST(CMMFAudioInput*, &aSource); + __ASSERT_ALWAYS( audioInput, Panic(ENoAudioInput)); + // [ lets load dev sound ] + User::LeaveIfError(audioInput->SourceThreadLogon( *this )); + } + else + { + User::Leave(KErrNotSupported); + } + + //[ its now safe to set the source ] + iDataSource = &aSource ; + + //[ assert the post condition ] + __ASSERT_ALWAYS(iDataSource, Panic(EMMFAudioControllerPanicDataSourceDoesNotExist)); + + iDataSource->SetSourcePrioritySettings(iPrioritySettings); + } + +/** + * AddDataSinkL + * + * Adds a data sink to the controller + * + * @param aSink + * + */ +void CMMFAudioController::AddDataSinkL(MDataSink& aSink) + { + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic( EBadStateToGetDataSink)); + + // [ precondition that the controller is stopped ] + if( State() != EStopped ) + User::Leave( KErrNotReady ); + + // [ assert precondition that sink does not exist ] + if (iDataSink) + User::Leave(KErrAlreadyExists); + + + // Note that this code is not generic for sinks + // It it only checks for file,des clips and audio outputs + // If a new sink type eg a Url Clip then this needs to be added to the supported source Uids + if ( SinkFormatRequired( aSink ) ) + {//the sink is a clip + + // Get the format from the Sink if possible from no specific supplier + TRAPD(err, iSinkFormat = CMMFFormatEncode::NewL(&aSink, KNullDesC)); + //[ we want to complete silently for KErrNotSupported + // because there is a possibility that the client + // wants to add the data format later, see audio api for + // a description of this feature] + if ((err != KErrNotSupported) && (err != KErrNone)) + { + User::Leave(err); + } + } + else if (aSink.DataSinkType()==KUidMmfAudioOutput) + { + + //[ ensure that the audio output has a pointer to dev sound ] + CMMFAudioOutput* audioOutput = STATIC_CAST(CMMFAudioOutput*, &aSink); + __ASSERT_ALWAYS( audioOutput, Panic(ENoAudioOutput)); + // [ lets load dev sound ] + User::LeaveIfError(audioOutput->SinkThreadLogon( *this )); + if (IsSecureDrmModeL()) + { + User::LeaveIfError(audioOutput->SoundDevice().SetClientThreadInfo(ClientThreadIdL())); + } + } + else + { + User::Leave(KErrNotSupported); + } + + //[ now that we are sure we have not left we can update the sink + // transactionally ] + iDataSink = &aSink; + + // [ assert post conditions that a sink has been added ] + __ASSERT_ALWAYS(iDataSink, Panic(EMMFAudioControllerPanicDataSinkDoesNotExist)); + + iDataSink->SetSinkPrioritySettings(iPrioritySettings); + } + +/** + * PrimeL + * + * If Prime fails the client should reset the controller + * because as noted below this code is not transactional. + * + */ +void CMMFAudioController::PrimeL() + { + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic( EBadStateForPrime)); + + //[ assert the precondition ( in a friendly way for this api + // that we are either stopped or primed already ] + if(!(( State() == EStopped ) || (State() == EPrimed ))) + User::Leave( KErrNotReady ); + + // [ precondition we have a data source & sink ] + __ASSERT_ALWAYS( iDataSource, Panic( ENoDataSource)); + __ASSERT_ALWAYS( iDataSink, Panic( ENoDataSink)); + + + //[ precondition that we need a source format ] + if ( SourceFormatRequired(*iDataSource) && !(iSourceFormat)) + User::Leave( KErrNotSupported ); + + // [ check the precondition if we need a data sink format ] + if ( SinkFormatRequired(*iDataSink) && !( iSinkFormat )) + { + User::Leave( KErrNotSupported ); + } + + // [ ideally this code should be transaction based and + // if failure occurs we roll back to the previous state + // in the code below this is not the case and the controller + // can be left in an unstable state should any part of prime fail] + if (iState == EStopped) + { //datapath propagates prime to sink & source + + NegotiateL(); + + if (!iSourceAndSinkAdded) + { + //add data source and sinks to datapath - Note cant do this in AddDataSource/Sink + //because the sources and sinks aren't configured at this point + if (iSourceFormat) + iDataPath->AddDataSourceL(iSourceFormat); + else if (iDataSource) + iDataPath->AddDataSourceL(iDataSource); + if (iSinkFormat) + iDataPath->AddDataSinkL(iSinkFormat); + else if (iDataSink) + iDataPath->AddDataSinkL(iDataSink); + iSourceAndSinkAdded = ETrue ; + } + + iDataPath->PrimeL(); + + if (iSourceFormat) + { + //in case of imaadpcm format set the output block length + + TFourCC sourceFourCC = iSourceFormat->SourceDataTypeCode(TMediaId(KUidMediaTypeAudio)); + if ((sourceFourCC == KMMFFourCCCodeIMAD) && iSourceFormatSupportsCustomInterfaces) + { + CMMFFormatDecode2* decode2 = static_cast(iSourceFormat); + MMMFDecodeCustomInterfaceBlockLength* formatBlockLengthCI = static_cast(decode2->CustomInterface(KUidCustomInterfaceMmfDecodeBlockLength)); + if (formatBlockLengthCI) + { + TInt blockLength = formatBlockLengthCI->FileBlockLength(); + TInt err = iDataPath->SetBlockLength(blockLength); + + if ((err != KErrNone) && (iDataSink)) + { + MMMFAudioOutput* audioOutput = static_cast(iDataSink); + MMMFDevSoundCustomInterfaceFileBlockLength* fileBlockLengthCI = static_cast(audioOutput->SoundDevice().CustomInterface(KUidCustomInterfaceDevSoundFileBlockLength)); + + if (fileBlockLengthCI) + { + fileBlockLengthCI->SetFileBlockLength(blockLength); + err = KErrNone; + } + } + User::LeaveIfError(err); + } + } + } + + if ((iSinkFormat) && (!iSourceFormat)) + {//we are recording to a clip so the data path position is the sink + //need to set datapath position to end of format pos (incase sink clip already exists + TTimeIntervalMicroSeconds duration = iSinkFormat->Duration(iMediaId); + if (duration != TTimeIntervalMicroSeconds(0)) + {//the file already exists and has a duration so set data path position to the end of the file + iDataPath->SetPositionL(duration); + } + } + //[ it is now safe to make the transition to primed ] + SetState( EPrimed ); + } + else if (State() == EPrimed) + { //controller is already primed so just pass prime onto DP + iDataPath->PrimeL(); + } + + if (iDataSource->DataSourceType()==KUidMmfFileSource) + { + CMMFFile* file = static_cast(iDataSource); + // we only support protected files for playback + if (iDataSink->DataSinkType()!=KUidMmfAudioOutput && file->IsProtectedL()) + User::Leave(KErrNotSupported); + } + + //[ assert the post condition that we are in the state primed] + __ASSERT_ALWAYS( SetState( EPrimed ), Panic( EPostConditionViolation )); + // [ assert the invariant] + __ASSERT_ALWAYS( Invariant(), Panic( EStateNotPrimed ) ); + } + +/** + * ResetL + * This method resets the controller + * + */ +void CMMFAudioController::ResetL() + { + __ASSERT_ALWAYS( Invariant(), Panic( EBadStateToReset ) ); + iIsPreemptionPause = EFalse; + // Stop recording if it's not stopped, + if (State() != EStopped) + { + iDataPath->Stop(); + SetState(EStopped); + } + iIsPaused = EFalse; + + // Remove references to source and sink + iDataPath->ResetL(); + + delete iSourceFormat; iSourceFormat = NULL ; + delete iSinkFormat; iSinkFormat = NULL ; + + //[ ensure loggoff of source and sink ] + iDataSource = NULL ; + iDataSink = NULL ; + iSourceAndSinkAdded = EFalse; + + // [ assert the invariant] + __ASSERT_ALWAYS( Invariant(), Panic( EBadResetState ) ); + + // [ assert the post condition + // state == stopped + // iDataSource is NULL + // iSourceFormat is NULL + // iSinkFormat is NULL ] + __ASSERT_ALWAYS( ResetPostCondition(), Panic( EBadReset )); + __ASSERT_ALWAYS( Invariant(), Panic(EBadState)); + } + +/** +* ResetPostCondition +* This function determnines if the reset post condition is valid +* @internalTechnology +*/ +TBool CMMFAudioController::ResetPostCondition() const + { + + TBool result = EFalse ; + if((iSourceFormat == NULL) && + (iDataSink == NULL) && + (iDataSource == NULL) && + (iSinkFormat == NULL) && + (State() == EStopped)) + { + result = ETrue; + } + + return result; + } + + +/** + * + * PlayL + * + */ +void CMMFAudioController::PlayL() + { + // [ assert the precondition that the + // play command is only activated in the primed state] + if ( State() != EPrimed) + { + User::Leave(KErrNotReady); + } + + // [ assert the Invariant ] + __ASSERT_ALWAYS( Invariant(), Panic(EStateNotReadyToPlay)); + + // if the position has already been set to the file's duration or + // beyond, then don't bother getting the datapath to play - this + // avoids sending empty buffers to DevSound + if (iDataSink->DataSinkType() == KUidMmfAudioOutput && + PositionL() >= DurationL()) + { + SendEventToClient(TMMFEvent(KMMFEventCategoryPlaybackComplete, KErrNone)); + return; + } + + // Execute play intent + // This must be done after PlayL, as the file might not be open yet + if(!iIsPreemptionPause) + { + if (!iDisableAutoIntent && iDataSource->DataSourceType()==KUidMmfFileSource ) + { + CMMFFile* file = static_cast(iDataSource); + TInt err = file->ExecuteIntent(iIsPaused? ContentAccess::EContinue : ContentAccess::EPlay); + if (err != KErrNone) + { + User::Leave(err); + } + } + } + //[datapath propogates play to sink & source] + iDataPath->PlayL(); + iIsPreemptionPause = EFalse; + iIsPaused = EFalse; + SetState( EPlaying ); + + //[ assert the post condition we are playing ] + //No - this assumption is not always true if an error occurs eg OOM + //the state could be EStopped + // __ASSERT_ALWAYS( (State() == EPlaying ), Panic( EBadState)); + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic(EBadPlayState)); + } + +/** + * PauseL + * + */ +void CMMFAudioController::PauseL() + { + // [ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic(EBadStateToPause)); + + //[ assert the precondition that we are playing ] + if ( State() != EPlaying) + { + User::Leave(KErrNotReady); + } + if(!iIsPreemptionPause) + { + if (!iDisableAutoIntent && iDataSource->DataSourceType()==KUidMmfFileSource) + { + CMMFFile* file = static_cast(iDataSource); + TInt err = file->ExecuteIntent(ContentAccess::EPause); + if (err != KErrNone) + { + User::Leave(err); + } + } + } + iIsPaused = ETrue; + //[ datapath propogates pause to sink & source ] + if(iIsPreemptionPause) + { + iDataPath->PreEmptionPause(); + } + else + { + iDataPath->Pause(); + } + SetState(EPrimed); + + //[ assert the post condition we are primed ] + __ASSERT_ALWAYS( (State() == EPrimed ), Panic( EBadState)); + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic(EBadPauseState)); + } + +/** + * StopL + * + */ +void CMMFAudioController::StopL(TMMFMessage& aMessage) + { + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic(EBadStateToStop)); + // [ precondition that we are not already stopped + // && if we are stopped do nothing. + //If we are stopping a recording, we need to give the datapath chance to + //process that data which has already been captured. We therefore stay in the EPlaying + //state, but use iStoppingRecording to indicate that we are stopping. + + if ((State() != EStopped) && !iStoppingRecording) + { + if((State() == EPlaying) && (iDataSource->DataSourceType()==KUidMmfAudioInput)) //we are recording + { + // datapath is requested to stop recording but process any alreay captured buffers, + // the pause method is used for this purpose and as such, the data path must + // determine that it is recording to be able to act accordingly. + // aMessgae is not completed until datapath advises that it has completed. + iDataPath->Pause(); + iStoppingMessage = CMMFMessageHolder::NewL(aMessage); + iStoppingRecording = ETrue; + } + else if(((State() == EPlaying) || iIsPaused) && (iDataSink->DataSinkType()==KUidMmfAudioOutput)) //we are playing + { + if (!iDisableAutoIntent && iDataSource->DataSourceType()==KUidMmfFileSource) + { + CMMFFile* file = static_cast(iDataSource); + file->ExecuteIntent(ContentAccess::EStop); + } + // datapath propogates stop to sink & source + iDataPath->Stop(); + SetState(EStopped); + } + + else + { + // datapath propogates stop to sink & source + iDataPath->Stop(); + SetState(EStopped); + } + } + iIsPaused = EFalse; + iIsPreemptionPause = EFalse; + //complete message as request is complete. + if(State() == EStopped && !IsUnderTest()) + { + aMessage.Complete(KErrNone); + } + + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic(EBadStopState)); + } + +/** + * PositionL + * Preconditions: + * The Controller is in the state EPrimed + * @return TTimeIntervalMicroSeconds + * + */ +TTimeIntervalMicroSeconds CMMFAudioController::PositionL() const + { + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic(EBadStateToPosition)); + // [ precondition that we are playing or primed ] + if( !((State() == EPrimed) || (State() == EPlaying))) + User::Leave(KErrNotReady); + + TTimeIntervalMicroSeconds position = iDataPath->Position(); + + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic(EBadStatePosition)); + + return position; + } + +/** +* SetPositionL +* +* @param aPosition +* +*/ +void CMMFAudioController::SetPositionL(const TTimeIntervalMicroSeconds& aPosition) + { + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic(EBadStateToSetPosition)); + + // [ precondition that we are not already stopped ] + if (iState == EStopped) + User::Leave(KErrNotReady); + + //[ precondition that the position is >= 0 && <= Duration ] + { + TTimeIntervalMicroSeconds theDuration(0); + if (iSourceFormat) + { //if the source is a clip then the duration always refers to the source - even if the sink is a clip + theDuration = iSourceFormat->Duration(iMediaId); + } + else if (iSinkFormat) + { //duration of recorded clip + theDuration = iSinkFormat->Duration(iMediaId); + } + TTimeIntervalMicroSeconds theStart(0); + if( ( aPosition < theStart) || ( aPosition > theDuration) ) + //[ invalid position before start and after end] + User::Leave(KErrArgument); + } + + //[ set the position on the data path ] + + // if we're already playing, flush all the buffers by calling Stop(), + // PrimeL() and then PlayL() - otherwise we could be waiting a long time. + if (iDataSink->DataSinkType() == KUidMmfAudioOutput && iState == EPlaying) + { + CMMFAudioOutput* audioOutput = static_cast(iDataSink); + if(!audioOutput->IsResumeSupported()) + { + iDataPath->Stop(); + SetState(EStopped); + PrimeL(); + iDataPath->SetPositionL(aPosition); + iDataPath->RetainRepeatInfo(); + PlayL(); + } + else + { + iDataPath->Pause(); + // This empty buffers + User::LeaveIfError(audioOutput->SoundDevice().EmptyBuffers()); + iDataPath->SetPositionL(aPosition); + iDataPath->RetainRepeatInfo(); + // This does a DevSound resume + iDataPath->PlayL(); + } + } + else + iDataPath->SetPositionL(aPosition); + + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic(EBadStateSetPosition)); + + // [ post condition not checked ] + //[ we do not compare the set position with get postion + // because the interface to do so is poor ] + } + +/** +* +* DurationL +* +* @returns TTimeIntervalMicroSeconds +* +*/ +TTimeIntervalMicroSeconds CMMFAudioController::DurationL() const + { + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic(EBadStateToDuration)); + + + // [ assert we have a format that supports duration ] + if( !( iSourceFormat || iSinkFormat ) ) + User::Leave(KErrNotSupported); + + //[ now do the real work of getting the duration ] + // ------------------------------------------------ + TTimeIntervalMicroSeconds theDuration(0); + if (iSourceFormat) + { //if the source is a clip then the duration always refers to the source - even if the sink is a clip + theDuration = iSourceFormat->Duration(iMediaId); + } + else if (iSinkFormat) + { //duration of recorded clip + theDuration = iSinkFormat->Duration(iMediaId); + } + + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic(EBadStateDuration)); + + return theDuration; + } + +/** +* +* GetNumberOfMetaDataEntriesL +* +* @param "TInt" +* +*/ +void CMMFAudioController::GetNumberOfMetaDataEntriesL(TInt& aNumberOfEntries ) + { + + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic(EBadStateToGetNumberOfMetaDataEntries)); + + //[ precondition that we are in the primed state or stopped ] + if( !((State() == EPrimed) || ( State() == EStopped))) + User::Leave(KErrNotReady); + + // [ precondition there is a sink format ] + if (!iDataSink) + User::Leave(KErrNotSupported); + + // [ precondition the sink format is an encode format ] + if ((iDataSink->DataSinkType()!=KUidMmfAudioOutput) && + (iDataSource->DataSourceType()!= KUidMmfAudioInput) ) + User::Leave(KErrNotSupported); + + if (iDataSink->DataSinkType()==KUidMmfAudioOutput) + { + + //[ precondition the format exists ] + if( !iSourceFormat ) + User::Leave(KErrNotSupported); + + //[ Get the Number of meta data entries from the sink format ] + iSourceFormat->GetNumberOfMetaDataEntriesL( aNumberOfEntries ); + } + else if (iDataSource->DataSourceType()==KUidMmfAudioInput) + { + if( !iSinkFormat ) + User::Leave(KErrNotSupported); + + iSinkFormat->GetNumberOfMetaDataEntriesL( aNumberOfEntries ); + } + + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic(EBadStateGetNumberOfMetaDataEntries)); + + } + +/** +* GetMetaDataEntryL +* @param aIndex +* @returns "CMMFMetaDataEntry*" +*/ +CMMFMetaDataEntry* CMMFAudioController::GetMetaDataEntryL(TInt aIndex ) + { + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic(EBadStateToGetMetaDataEntries)); + + //[ precondition that we are in the primed state or stopped ] + if( !((State() == EPrimed) || ( State() == EStopped))) + User::Leave(KErrNotReady); + + // [ precondition there is a sink format ] + if (!iDataSink) + User::Leave(KErrNotSupported); + + iDataSink->DataSinkType(); + iDataSource->DataSourceType(); + + // [ precondition the sink or source is either an audio output or input ] + if ((iDataSink->DataSinkType()!= KUidMmfAudioOutput) && + (iDataSource->DataSourceType()!= KUidMmfAudioInput )) + User::Leave(KErrNotSupported); + + //[ Get the meta data entry from the sink format ] + CMMFMetaDataEntry* theEntry = NULL; + + if (iDataSink->DataSinkType()==KUidMmfAudioOutput) + { + //[ precondition the format exists ] + if( !iSourceFormat ) + User::Leave(KErrNotSupported); + + //[ Get the Number of meta data entries from the sink format ] + theEntry = iSourceFormat->MetaDataEntryL(aIndex); + } + else if (iDataSource->DataSourceType()==KUidMmfAudioInput) + { + //[ precondition the format exits ] + if( !iSinkFormat ) + User::Leave(KErrNotSupported); + theEntry = iSinkFormat->MetaDataEntryL(aIndex); + } + + //[ assert the post condition that the entry is not null ] + __ASSERT_ALWAYS( theEntry, Panic(EMetaEntryIsNull)); + + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic(EBadStateGetMetaDataEntries)); + + return theEntry; + } + +/** +* RemoveDataSourceL +* @param aDataSource +* +*/ +void CMMFAudioController::RemoveDataSourceL(MDataSource& aDataSource ) + { + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic(ENotReadyForDataSourceRemoval) ); + + //[ precondition is that we have a data source ] + if( !iDataSource ) + User::Leave(KErrNotReady); + + //[precondition the data source is the data source we have] + if( iDataSource != &aDataSource ) + User::Leave(KErrArgument); + + //[ the controller is in the stopped state ] + if(State() != EStopped) + User::Leave(KErrNotReady); + + //[ remove the data sink from the controller and delete the format] + if( iSourceAndSinkAdded ) + { + __ASSERT_ALWAYS( iDataPath, Panic( EBadState )); + //[ Remove references to source and sink ] + iDataPath->ResetL(); + iSourceAndSinkAdded = EFalse ; + } + + // [ delete the data sink and format ] + iDataSource = NULL ; + delete iSourceFormat; + iSourceFormat = NULL; + + // [ assert postcondition we are stopped ] + __ASSERT_ALWAYS( (State() == EStopped), Panic(EPostConditionViolation) ); + + //[ assert postcondition the SourceAndSinkAdded is false ] + __ASSERT_ALWAYS( !iSourceAndSinkAdded, Panic( EPostConditionViolation )); + + //[ assert postcondition the data sinkformat is null ] + __ASSERT_ALWAYS( (iSourceFormat == NULL ), Panic( EPostConditionViolation )); + + //[ assert postcondition the data sink is null ] + __ASSERT_ALWAYS( (iDataSource == NULL ), Panic( EPostConditionViolation )); + + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic(EBadDataSourceRemoval)); + + } + +/** +* RemoveDataSinkL +* +* @param aDataSink +* +*/ +void CMMFAudioController::RemoveDataSinkL(MDataSink& aDataSink ) + { + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic(ENotReadyForDataSinkRemoval) ); + + //[ precondition is that we have a data sink ] + if( !iDataSink ) + User::Leave(KErrNotSupported); + + //[precondition the data sink is the data sink we have] + if( iDataSink != &aDataSink ) + User::Leave(KErrNotSupported); + + //[ the controller is in the stopped state ] + if(State() != EStopped) + User::Leave(KErrNotReady); + + //[ remove the data sink from the controller and delete the format] + if( iSourceAndSinkAdded ) + { + __ASSERT_ALWAYS( iDataPath, Panic( EBadState )); + //[ Remove references to source and sink ] + iDataPath->ResetL(); + iSourceAndSinkAdded = EFalse ; + } + + // [ reset data sink referenece and remove the format ] + iDataSink = NULL ; + delete iSinkFormat; + iSinkFormat = NULL; + + // [ assert postcondition we are stopped ] + __ASSERT_ALWAYS( (State() == EStopped), Panic(EPostConditionViolation) ); + + //[ assert postcondition the SourceAndSinkAdded is false ] + __ASSERT_ALWAYS( !iSourceAndSinkAdded, Panic( EPostConditionViolation )); + + //[ assert postcondition the data sinkformat is null ] + __ASSERT_ALWAYS( (iSinkFormat == NULL ), Panic( EPostConditionViolation )); + + //[ assert postcondition the data sink is null ] + __ASSERT_ALWAYS( (iDataSink == NULL ), Panic( EPostConditionViolation )); + + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic(EBadDataSinkRemoval)); + } + +/** + * CustomCommand + * @param aMessage + */ +void CMMFAudioController::CustomCommand(TMMFMessage& aMessage) + { + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic(ENotReadyForCustomCommand)); + // [ We do not have any custom commands ] + aMessage.Complete(KErrNotSupported); + } + +/** +* NegotiateL +* +*/ +void CMMFAudioController::NegotiateL() + { + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic(EBadStateToNegotiate)); + + //utility function used by custom to negotiate source sink settings after a change + if ((iSourceFormat)&&(iSinkFormat)) //convert + { + iSinkFormat->NegotiateL(*iSourceFormat); + iSourceFormat->NegotiateSourceL(*iSinkFormat); + iSinkFormat->NegotiateL(*iSourceFormat); + + // check for upsampling attempts + if (iSinkFormat->SampleRate() > iSourceFormat->SampleRate()) + { + // we don't support upsampling + User::Leave( KErrNotSupported ); + } + } + else if ((iDataSource)&&(iSinkFormat)) //record + { + // need two step negotiation for record + // first try to set the audio input settings to match the required settings for recording + iDataSource->NegotiateSourceL(*iSinkFormat); + // now call negotiateL on the sink in order to tell it what the audio input was set to. + iSinkFormat->NegotiateL(*iDataSource); + } + else if ((iSourceFormat)&&(iDataSink)) //play + { + iDataSink->NegotiateL(*iSourceFormat); + } + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic(EBadStateAfterNegotiate)); + } + +/** + * SetPrioritySettings + * + * @param aPrioritySettings + */ +void CMMFAudioController::SetPrioritySettings(const TMMFPrioritySettings& aPrioritySettings) + { + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic(EBadStateToSetPriority)); + + //[ update the priority settings of the controller] + iPrioritySettings = aPrioritySettings; + + //pass settings on to source and sink + if (iDataSource) + { + iDataSource->SetSourcePrioritySettings(iPrioritySettings); + } + if (iDataSink) + { + iDataSink->SetSinkPrioritySettings(iPrioritySettings); + } + + // assert the post condition + //__ASSERT_ALWAYS( (iPrioritySettings == aPrioritySettings), Panic( )); + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic(EBadPriorityState)); + } + +/** + * SendEventToClient + * + * @param aEvent + */ +TInt CMMFAudioController::SendEventToClient(const TMMFEvent& aEvent) + { + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic(EBadStateToSendEventToClient)); + + TMMFEvent controllerEvent; + //Were going to stop playing, force event type to be the correct type + controllerEvent.iEventType = KMMFEventCategoryPlaybackComplete; + controllerEvent.iErrorCode = aEvent.iErrorCode; + + + + //If we receive KErrNone from the DataPath, it indicates that it has + //successfully completed playing/converting/recording. + if ((aEvent.iEventType == KMMFEventCategoryPlaybackComplete) && + (aEvent.iErrorCode == KErrNone)) + { + if(iStoppingRecording) + { + iStoppingRecording = EFalse; + iDataPath->Stop(); + SetState( EStopped ); + + //complete the clients stop request + iStoppingMessage->Complete(KErrNone); + delete iStoppingMessage; iStoppingMessage=NULL; + + //we don't want to send an event to the client + return KErrNone; + } + else + {//datapath has reached end of file so set internal state to primed + SetState( EPrimed ); + } + } + //DevCR KEVN-7T5EHA + //If the client has not registered for the ARN, + //and a pre-emption happens we need to goto the Pause state + //instead of the Stop state. this should happen only in the case of playback. + //In case of recoding we goto the stop state. + else if(!iRegisterARN && + (aEvent.iErrorCode == KErrAccessDenied || aEvent.iErrorCode == KErrInUse ||aEvent.iErrorCode == KErrDied) + && (iDataSink->DataSinkType()==KUidMmfAudioOutput)) + { + //setting iIsPreemptionPause to true so that PauseL can make differentiate it from normal pause. + iIsPreemptionPause = ETrue; + TRAPD(err,PauseL()); + if(err != KErrNone) + { + iDataPath->Stop(); + SetState( EStopped ); + iIsPreemptionPause = EFalse; + } + } + else + { + if ( State()!= EStopped) + { + //datapath propogates stop to sink & source + iDataPath->Stop(); + SetState( EStopped ); + + if(iStoppingRecording) + {// an error has occurred while we were waiting for recording to stop, + //must complete clients request + iStoppingRecording = EFalse; + iStoppingMessage->Complete(aEvent.iErrorCode); + delete iStoppingMessage; iStoppingMessage=NULL; + } + } + } + if(!iIsPreemptionPause) + { + //should call ExecuteIntent to tell the DRM agent that playback has stopped + if (aEvent.iEventType == KMMFEventCategoryPlaybackComplete) + { + if ((iDataSink->DataSinkType() == KUidMmfAudioOutput)) + { + if (!iDisableAutoIntent && iDataSource->DataSourceType()==KUidMmfFileSource) + { + CMMFFile* file = static_cast(iDataSource); + file->ExecuteIntent(ContentAccess::EStop); + } + } + } + } + + //now send event to client... + TInt result = KErrNone; + if(aEvent.iEventType == KMMFEventCategoryAudioResourceAvailable) + { + result = DoSendEventToClient(aEvent); + } + else + { + result = DoSendEventToClient(controllerEvent); + } + + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic(EBadStateAfterSendEventToClient)); + + return result; + } + + +/** +* MapdSetVolumeL +* +* @param aVolume +* +*/ +void CMMFAudioController::MapdSetVolumeL(TInt aVolume) + { + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic(EBadStateToSetVolume)); + + // [ precondition is true for state + // we can set the volume in any state ] + + //[ precondition we have a data sink ] + if (!iDataSink) + User::Leave(KErrNotReady); + + // [ precondition that the data sink is an audio output ] + // Make sure that iDataSink is an Audio Output + if (iDataSink->DataSinkType() != KUidMmfAudioOutput) + User::Leave(KErrNotSupported); + + MMMFAudioOutput* audioOutput = STATIC_CAST(MMMFAudioOutput*, iDataSink); + + // [ assert the precondition that aVolume is in range ] + TInt maxVolume = audioOutput->SoundDevice().MaxVolume(); + if( ( aVolume < 0 ) || ( aVolume > maxVolume )) + User::Leave(KErrArgument); + + //[ set the volume on the device ] + audioOutput->SoundDevice().SetVolume(aVolume); + + //[ assert the post condition volume is equal to a volume] + TInt soundVolume = 0; + soundVolume = audioOutput->SoundDevice().Volume(); + + __ASSERT_ALWAYS( ( soundVolume == aVolume), Panic(EPostConditionViolation)); + + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic(EBadStateAfterVolumeSet)); + } + +/** +* +* MapdGetMaxVolumeL +* +* @param aMaxVolume +* +*/ +void CMMFAudioController::MapdGetMaxVolumeL(TInt& aMaxVolume) + { + // [ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic(EBadStateToGetMaxVolume)); + + //[ we can get max volume in any state ] + + // [ precondition we must have a data sink ] + if (!iDataSink) + User::Leave(KErrNotReady); + + //[ precondition the sink must be an audio output] + // Make sure that iDataSink is an Audio Output + if (iDataSink->DataSinkType() != KUidMmfAudioOutput) + User::Leave(KErrNotSupported); + + //[ get the volume from the device ] + MMMFAudioOutput* audioOutput = STATIC_CAST(MMMFAudioOutput*, iDataSink); + aMaxVolume = audioOutput->SoundDevice().MaxVolume(); + + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic(EBadStateAfterGetMaxVolume)); + + } + + +/** +* +* MapdGetVolumeL +* +* @param aVolume +* +*/ +void CMMFAudioController::MapdGetVolumeL(TInt& aVolume) + { + // [ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic(EBadStateToGetVolume)); + + //[ precondition that we have a data sink ] + if (!iDataSink) + User::Leave(KErrNotReady); + + //[ precondition iDataSink is an Audio Output ] + if (iDataSink->DataSinkType() != KUidMmfAudioOutput) + User::Leave(KErrNotSupported); + + // [ get the volume ] + MMMFAudioOutput* audioOutput = STATIC_CAST(MMMFAudioOutput*, iDataSink); + aVolume = audioOutput->SoundDevice().Volume(); + + // [ assert precondition that the volume is in range + // 0.. aMaxVolume ] + TInt aMaxVolume = audioOutput->SoundDevice().MaxVolume(); + __ASSERT_ALWAYS( (aVolume <= aMaxVolume), Panic(EBadState)); + __ASSERT_ALWAYS( (aVolume >= 0), Panic(EBadState)); + + // [ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic(EBadStateAfterGetVolume)); + + } + +/** +* +* MapdSetVolumeRampL +* +* @param aRampDuration +* +*/ +void CMMFAudioController::MapdSetVolumeRampL(const TTimeIntervalMicroSeconds& aRampDuration) + { + // [ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic(EBadStateToSetVolumeRamp)); + + //[ precondition that we have a data sink ] + if (!iDataSink) + User::Leave(KErrNotReady); + + // [ precondition iDataSink is an Audio Output ] + if (iDataSink->DataSinkType() != KUidMmfAudioOutput) + User::Leave(KErrNotSupported); + + //[ set the volume ramp ] + MMMFAudioOutput* audioOutput = STATIC_CAST(MMMFAudioOutput*, iDataSink); + audioOutput->SoundDevice().SetVolumeRamp(aRampDuration); + + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic(EBadStateAfterSetVolumeRamp)); + + } + + +/** +* +* MapdSetBalanceL +* +* @param aBalance +* +*/ +void CMMFAudioController::MapdSetBalanceL(TInt aBalance) + { + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic( EBadStateToSetBalance)); + + // [ precondition is that we have a data sink ] + if (!iDataSink) + User::Leave(KErrNotReady); + + // [ precondition is that the data sink is an audio output] + if (iDataSink->DataSinkType() != KUidMmfAudioOutput) + User::Leave(KErrNotSupported); + + //[ get the audio output ] + MMMFAudioOutput* audioOutput = STATIC_CAST(MMMFAudioOutput*, iDataSink); + + // [ separate out left and right balance ] + TInt left = 0; + TInt right = 0; + CalculateLeftRightBalance( left, right, aBalance ); + + //[ set the balance ] + audioOutput->SoundDevice().SetPlayBalanceL(left, right); + + // [assert the post condition that the balance is set correctly] + TInt rightBalance = 0; + TInt leftBalance = 0; + audioOutput->SoundDevice().GetPlayBalanceL(leftBalance, rightBalance); + + //[ assert post condition holds] + TBool postCondition = (( rightBalance == right) && ( leftBalance == left)); + __ASSERT_ALWAYS( postCondition, Panic( EPostConditionViolation ) ); + + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic( EBadStateAfterSetBalance)); + } + +/** +* CalculateLeftRightBalance +* @internalTechnology +* @param aLeft +* @param aRight +* @param aBalance +* Preconditions: +* !(aBalance < KMMFBalanceMaxLeft || aBalance > KMMFBalanceMaxRight) +* y = m x + c +* aLeft = m ( aBalance ) + c +* when aBalance = KMMFBalanceMaxLeft aLeft = 100 +* when aBalance = KMMFBalanceMaxRight aLeft = 0 +* 100 = m( KMMFBalanceMaxLeft ) + c +* 0 = m( KMMFBalanceMaxRight ) + c +* c = -(KMMFBalanceMaxRight) m +* 100 = m(KMMFBalanceMaxLeft ) - m(KMMFBalanceMaxRight) +* m = 100/(KMMFBalanceMaxLeft - KMMFBalanceMaxRight ) +* c = -(KMMFBalanceMaxRight) * 100 /(KMMFBalanceMaxLeft - KMMFBalanceMaxRight ) +* aLeft = ( aBalance - KMMFBalanceMaxRight ) * 100 /( KMMFBalanceMaxLeft - KMMFBalanceMaxRight ) +*/ +void CMMFAudioController::CalculateLeftRightBalance( TInt& aLeft, TInt& aRight, TInt aBalance ) const + { + // Check the balance is within limits & modify to min or max values if necessary + if (aBalance < KMMFBalanceMaxLeft) + aBalance = KMMFBalanceMaxLeft; + if (aBalance > KMMFBalanceMaxRight) + aBalance = KMMFBalanceMaxRight; + + //[ Now separate percentage balances out from aBalance ] + aLeft = (100 * (aBalance-KMMFBalanceMaxRight)) / (KMMFBalanceMaxLeft-KMMFBalanceMaxRight); + aRight = 100 - aLeft; + + //[ assert post condition that left and right are within range ] + __ASSERT_ALWAYS( ( (aLeft <= 100) && (aLeft >= 0) ), Panic(EPostConditionViolation)); + __ASSERT_ALWAYS( ( (aRight <= 100) && (aRight >= 0) ), Panic(EPostConditionViolation)); + } + + +/** +* MapdGetBalanceL +* @param aBalance +* +*/ +void CMMFAudioController::MapdGetBalanceL(TInt& aBalance) + { + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic(EBadStateToGetBalance)); + + //[ precondition that we have a sink] + if (!iDataSink) + User::Leave(KErrNotReady); + + // [ iDataSink is an Audio Output ] + if (iDataSink->DataSinkType() != KUidMmfAudioOutput) + User::Leave(KErrNotSupported); + + // [ get the play balance ] + MMMFAudioOutput* audioOutput = STATIC_CAST(MMMFAudioOutput*, iDataSink); + TInt left = 50; // arbitrary values + TInt right = 50; + audioOutput->SoundDevice().GetPlayBalanceL(left, right); + CalculateBalance( aBalance, left, right ); + + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic(EBadStateAfterGetBalance)); + } + +/** +* CalculateBalance +* @param aBalance +* @param aLeft +* @param aRight +* +* follows a simple straight line transformation +* y = m x + c +* m = (KMMFBalanceMaxLeft-KMMFBalanceMaxRight)/ 100 +* c = KMMFBalanceMaxRight +* by substitution +* when aLeft = 0 +* KMMFBalanceMaxRight = m * 0 + c +* c = KMMFBalanceMaxRight +* when aLeft = 100 +* KMMFBalanceMaxLeft = m * 100 + KMMFBalanceMaxRight +* m = ( KMMFBalanceMaxLeft - KMMFBalanceMaxRight ) /100 +*/ +void CMMFAudioController::CalculateBalance( TInt& aBalance, TInt aLeft, TInt aRight ) const + { + //[ assert pre conditions ] + __ASSERT_ALWAYS( (( 0 <= aLeft) && ( 100 >= aLeft)), Panic( EBadArgument) ); + __ASSERT_ALWAYS( (( 0 <= aRight) && ( 100 >= aRight)), Panic( EBadArgument) ); + + if ((aLeft > 0) && (aRight > 0)) + { + __ASSERT_ALWAYS( (( aLeft + aRight ) == 100 ), Panic( EBadArgument )); + aBalance = (aLeft * (KMMFBalanceMaxLeft-KMMFBalanceMaxRight))/100 + KMMFBalanceMaxRight; + } + else if ((aLeft == 0) && (aRight == 0)) + { + aBalance = 0; + } + else if ((aLeft == 0) && (aRight > 0)) + { + aBalance = 100; + } + else if ((aLeft > 0) && (aRight == 0)) + { + aBalance = -100; + } + + //[ assert post condition that aBalance is within limits ] + __ASSERT_ALWAYS( !(aBalance < KMMFBalanceMaxLeft || aBalance > KMMFBalanceMaxRight), Panic(EBadArgument)); + + } + +/** +* MardSetGainL +* @param aGain +* +*/ +void CMMFAudioController::MardSetGainL(TInt aGain) + { + // [ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic(EBadStateToSetGain)); + + //[ precondition we are in the state stopped ] + if(State() != EStopped) + User::Leave(KErrNotReady); + + // [ assert the precondition that we have a data sink ] + if (!iDataSource) + User::Leave(KErrNotSupported); + + //[ assert the precondition that the data sink is an audio input ] + if (iDataSource->DataSourceType() != KUidMmfAudioInput) + User::Leave(KErrNotReady); + + // Set gain of sound device + MMMFAudioInput* audioInput = STATIC_CAST(MMMFAudioInput*, iDataSource); + audioInput->SoundDevice().SetGain(aGain); + + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic(EBadStateAfterGainSet)); + + } + +/** +* MardGetMaxGainL +* @param aMaxGain +* +*/ +void CMMFAudioController::MardGetMaxGainL(TInt& aMaxGain) + { + // [ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic(EBadStateToGetMaxGain)); + + // [ assert the precondition that we have a source ] + if (!iDataSource) + User::Leave(KErrNotReady); + + //[ assert the precondition that iDataSink is an Audio Input] + if (iDataSource->DataSourceType() != KUidMmfAudioInput) + User::Leave(KErrNotSupported); + + MMMFAudioInput* audioInput = STATIC_CAST(MMMFAudioInput*, iDataSource); + aMaxGain = audioInput->SoundDevice().MaxGain(); + + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic(EBadStateAfterGetMaxGain)); + + } + +/** +* MardGetGainL +* @param aGain +* +*/ +void CMMFAudioController::MardGetGainL(TInt& aGain) + { + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic(EBadStateToGetGain)); + + // [ assert the precondition that we have a sink ] + if (!iDataSource) + User::Leave(KErrNotReady); + + // [ assert the precondition that we have an audio input sink] + if (iDataSource->DataSourceType() != KUidMmfAudioInput) + User::Leave(KErrNotSupported); + + MMMFAudioInput* audioInput = STATIC_CAST(MMMFAudioInput*, iDataSource); + aGain = audioInput->SoundDevice().Gain(); + + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic(EBadStateAfterGetGain)); + } + + +/** + * + * MardSetBalanceL + * @param aBalance + */ +void CMMFAudioController::MardSetBalanceL(TInt aBalance) + { + // [ assert the invaraiant ] + __ASSERT_ALWAYS( Invariant(), Panic(EBadStateToSetGain)); + + // [ precondition is that we have a data source ] + if (!iDataSource) + { + User::Leave(KErrNotReady); + } + + // [ precondition is that the balance is in range ] + // Make sure aBalance is in the range -100 <-> 100 + if (aBalance < KMMFBalanceMaxLeft || aBalance > KMMFBalanceMaxRight) + User::Leave(KErrArgument); + + // [ precondition is that the data sink is an audio output] + if (iDataSource->DataSourceType() != KUidMmfAudioInput) + User::Leave(KErrNotSupported); + + + //[ get the audio output ] + MMMFAudioInput* audioInput = STATIC_CAST(MMMFAudioInput*, iDataSource); + + // [ separate out left and right balance ] + TInt left = 0; + TInt right = 0; + CalculateLeftRightBalance( left, right, aBalance ); + + //[ set the balance ] + audioInput->SoundDevice().SetRecordBalanceL(left, right); + + // [assert the post condition that the balance is set correctly] + TInt rightBalance = 0; + TInt leftBalance = 0; + audioInput->SoundDevice().GetRecordBalanceL(leftBalance, rightBalance); + + //[ assert post condition holds] + TBool postCondition = (( rightBalance == right) && ( leftBalance == left)); + __ASSERT_ALWAYS( postCondition, Panic( EPostConditionViolation ) ); + + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic( EBadStateAfterGainSet)); + + } + +/** +* +* MardGetBalanceL +* @param aBalance +* +*/ +void CMMFAudioController::MardGetBalanceL(TInt& aBalance) + { + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic(EBadStateToGetBalance)); + + // [ precondition is that we have a data source ] + if (!iDataSource) + { + User::Leave(KErrNotReady); + } + + // [ iDataSink is an Audio Output ] + if (iDataSource->DataSourceType() != KUidMmfAudioInput) + User::Leave(KErrNotSupported); + + // [ get the play balance ] + MMMFAudioInput* audioInput = STATIC_CAST(MMMFAudioInput*, iDataSource); + TInt left = 50; // arbitrary values + TInt right = 50; + audioInput->SoundDevice().GetRecordBalanceL(left, right); + CalculateBalance( aBalance, left, right ); + + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic(EBadStateAfterGetBalance)); + + } + +/** +* MapcSetPlaybackWindowL +* @param aStart +* @param aEnd +* +*/ +void CMMFAudioController::MapcSetPlaybackWindowL(const TTimeIntervalMicroSeconds& aStart, const TTimeIntervalMicroSeconds& aEnd) + { + iDataPath->SetPlayWindowL(aStart, aEnd); + } + +/** +* MapcDeletePlaybackWindowL +*/ +void CMMFAudioController::MapcDeletePlaybackWindowL() + { + iDataPath->ClearPlayWindowL(); + } + + +/** +* MapcSetRepeatsL +* @param aRepeatNumberOfTimes +* @param aTrailingSilence +* +*/ + +TInt CMMFAudioController::MapcSetRepeats(TInt aRepeatNumberOfTimes, const TTimeIntervalMicroSeconds& aTrailingSilence) + { + TInt err = KErrNone; + if (!iDataSink) + { + err = KErrNotReady; + } + else if (iDataSink->DataSinkType() != KUidMmfAudioOutput) + { + err = KErrNotSupported; + } + else + { + MMMFAudioOutput* audioOutput = static_cast(iDataSink); + if(audioOutput->SoundDevice().QueryIgnoresUnderflow()) + { + iDataPath->SetRepeats(aRepeatNumberOfTimes,aTrailingSilence); + iDataPath->SetDrmProperties(iDataSource, &iDisableAutoIntent); + } + else + { + err = KErrNotSupported; + } + } + return err; + } + + +/** +* MapcGetLoadingProgressL +*/ +void CMMFAudioController::MapcGetLoadingProgressL(TInt& /*aPercentageComplete*/) + { + User::Leave(KErrNotSupported); + } + + +/** +* MarcGetRecordTimeAvailableL +* @param aTime +* +*/ +void CMMFAudioController::MarcGetRecordTimeAvailableL(TTimeIntervalMicroSeconds& aTime) + { + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic(EBadStateToGetRecordTimeAvailable)); + + //[ assert the precondition ( in a friendly way for this api + // that we minimally have a data sink ] + if( !iDataSink ) + User::Leave( KErrNotReady ); + + // Use the FormatEncode to get the bytes per second and the sink (clip) to get the bytes available + // return the calculated value. + if ((iDataSink->DataSinkType() != KUidMmfFileSink) && (iDataSink->DataSinkType() != KUidMmfDescriptorSink)) + User::Leave(KErrNotSupported) ; + + // [ max file size ] + //[ pre condition is that we have a sink ] + + // In order to get the record time available we need to take into consideration + // that there may be a max file size ] + TInt64 bytesFree = STATIC_CAST(CMMFClip*, iDataSink)->BytesFree() ; + TInt64 bytesPerSecond = TInt64(0); + //[ set default time available ] + aTime = TTimeIntervalMicroSeconds( 0 ) ; // just return zero + + if( iSinkFormat ) + { + TInt maxFileSize = STATIC_CAST(CMMFFormatEncode*, iSinkFormat)->MaximumClipSize(); + //[ if maxFileSize > 0 we need to limit the bytes free to this value - size ] + if( maxFileSize > 0 ) + { + // [ strangely the size of data written is a TInt ] + TInt fileSize = STATIC_CAST(CMMFClip*, iDataSink)->Size(); + bytesFree = maxFileSize - fileSize; + // [ note it can occur that the fileSize id greater than the MaxFileSize + // due to someone setting the max file size on an existing file ] + if( bytesFree < 0 ) bytesFree = 0; + __ASSERT_DEBUG( ( bytesFree <= maxFileSize), Panic( ENoMemoryToRecord) ); + } + bytesPerSecond = STATIC_CAST(CMMFFormatEncode*, iSinkFormat)->BytesPerSecond() ; + } + + //[ now lets perform the calculation of time available ] + if ( bytesPerSecond != TInt64(0) ) + { + aTime = TTimeIntervalMicroSeconds( bytesFree * KOneSecondInMicroSeconds / bytesPerSecond ) ; + } + + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic(EBadStateAfterGetRecordTimeAvailable)); + } + +/** +* MarcSetMaxDurationL +* @param aMaxDuration +*/ +void CMMFAudioController::MarcSetMaxDurationL(const TTimeIntervalMicroSeconds& ) + { + //[ this method is deprecated and no longer supported ] + User::Leave(KErrNotSupported); + } + +/** +* MarcSetMaxFileSizeL +* @param aFileSize +* @precondition +* The argument aFileSize must be greater than -1 +* zero is used as a sentinel value which means that the file +* can grow without limit +*/ +void CMMFAudioController::MarcSetMaxFileSizeL(TInt aFileSize ) + { + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic(EBadStateToGetMaxFileSize)); + + //[ assert the state is not playing since this opens open + // nefarious posibilities + if(State() == EPlaying ) + User::Leave( KErrNotReady ); + + //[ assert we have a sink format ] + if( !iSinkFormat ) + User::Leave( KErrNotReady ); + + //[ assert file size > -2, as a basic sanity filter + // 0 is the sentinel value which allows a file to grow + // as needed.] + // [We use -1 to reset the value set earlier.] + if( aFileSize < -1 ) + { + User::Leave( KErrArgument ); + } + + //[ pre condition is that we have a sink ] + STATIC_CAST(CMMFFormatEncode*, iSinkFormat)->SetMaximumClipSizeL( aFileSize ); + + // [ assert the post condition ] + // [since we have no means of querying the value + // we have to assume all went well for now or we left] + + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic(EBadStateAfterGetMaxFileSize)); + } + +/** +* MarcCropL +* @param aToEnd +*/ +void CMMFAudioController::MarcCropL(TBool aToEnd) + { + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic(EBadStateToCrop)); + + //[ precondition there is a sink format] + if (!iSinkFormat) + User::Leave(KErrNotSupported); + + iSinkFormat->CropL( PositionL(), aToEnd ); + + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic(EBadStateAfterCrop)); + } + +/** +* MarcAddMetaDataEntryL +* @param aNewEntry +*/ +void CMMFAudioController::MarcAddMetaDataEntryL(const CMMFMetaDataEntry& aNewEntry ) + { + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic(EBadStateToAddMetaDataEntry)); + + //[ precondition the format exists ] + if( !iSinkFormat ) + User::Leave(KErrNotSupported); + + //[ Add the meta data entry ] + iSinkFormat->AddMetaDataEntryL( aNewEntry ); + + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic(EBadStateAfterAddMetaDataEntry)); + + } + +/** +* MarcRemoveMetaDataEntryL +* @param aIndex +*/ +void CMMFAudioController::MarcRemoveMetaDataEntryL(TInt aIndex) + { + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic(EBadStateToRemoveMetaDataEntry)); + + //[ precondition that we are in the primed state ] + if( State() != EPrimed) + User::Leave(KErrNotReady); + + //[ precondition the format exists ] + if( !iSinkFormat ) + User::Leave(KErrNotSupported); + + //[ remove the meta data entry ] + iSinkFormat->RemoveMetaDataEntry( aIndex ); + + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic(EBadStateAfterRemoveMetaDataEntry)); + + } + +/** +* MarcReplaceMetaDataEntryL +* @param aIndex +* @param aNewEntry +*/ +void CMMFAudioController::MarcReplaceMetaDataEntryL(TInt aIndex, const CMMFMetaDataEntry& aNewEntry) + { + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic(EBadStateToReplaceMetaDataEntry)); + + //[ precondition that we are in the primed state ] + if( State() != EPrimed) + User::Leave(KErrNotReady); + + //[ precondition the format exists ] + if( !iSinkFormat ) + User::Leave(KErrNotSupported); + + //[ replace meta data entry ] + iSinkFormat->ReplaceMetaDataEntryL( aIndex, aNewEntry ); + + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic(EBadStateAfterReplaceMetaDataEntry)); + + } + +/** +* MacSetSourceSampleRateL +* @param aSampleRate +*/ +void CMMFAudioController::MacSetSourceSampleRateL(TUint aSampleRate) + { + // [ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic( EBadStateToSetSourceSampleRate)); + + // [ assert the precondition we are stopped ] + if( State() != EStopped ) + User::Leave(KErrNotReady); + + + if (iSourceFormat) + {//only applicable to formats + // don't throw an error if the clip already exists with a different sample rate + TInt error = iSourceFormat->SetSampleRate(aSampleRate); + if (error != KErrNone && error != KErrAlreadyExists) + User::Leave(error); + } + else + {//during recording, sample rate cannot be set directly on the datasource. It is set via NegotiateL + User::Leave(KErrNotSupported); + } + + // [assert the post condition ] + __ASSERT_ALWAYS( Invariant(), Panic( EBadStateAfterSetSourceSampleRate)); + + } + +/** +* MacSetSourceNumChannelsL +* @param aNumChannels +*/ +void CMMFAudioController::MacSetSourceNumChannelsL(TUint aNumChannels) + { + // [ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic( EBadStateToSetSourceNumChannels)); + + // [assert the precondition that we are stopped ] + if( State() != EStopped ) + User::Leave(KErrNotReady); + + if (iSourceFormat) + {//only applicable to formats + // don't throw an error if the clip already exists with a different number of channels + TInt error = iSourceFormat->SetNumChannels(aNumChannels); + if (error != KErrNone && error != KErrAlreadyExists) + User::Leave(error); + } + else + {//during recording, channels cannot be set directly on the datasource. It is set via NegotiateL + User::Leave(KErrNotSupported); + } + + // [ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic( EBadStateAfterSetSourceNumChannels)); + + } + +/** +* MacSetSourceFormatL +* @param aFormatUid +* +*/ +void CMMFAudioController::MacSetSourceFormatL(TUid aFormatUid) + { + //[ assert the invaraint ] + __ASSERT_ALWAYS( Invariant(), Panic( EBadStateToSetSourceFormat)); + + // [ precondition that the controller is stopped ] + if( State() != EStopped ) + User::Leave( KErrNotReady ); + + //[ precondition that the data source exists] + if (!iDataSource) + User::Leave(KErrNotReady); + + //[ precondition that we need a format ] + if( !SourceFormatRequired( *iDataSource ) ) + User::Leave(KErrNotSupported); //cant set source format if source isn't a clip + + //[ if the format exists and the uid of the requested + // format is the same as the existing format then simply + // return otherwise create a new format ] + if( !((iSourceFormat) && ( iSourceFormat->ImplementationUid() == aFormatUid))) + { + // [ delete the old format regardless ] + delete iSourceFormat; + iSourceFormat = NULL; + iSourceFormat = CMMFFormatDecode::NewL(aFormatUid, iDataSource); + } + + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic( EBadStateAfterSetSourceFormat)); + + //[ assert the post condition that a source format has been constructed ] + __ASSERT_ALWAYS( (iSourceFormat != NULL), Panic( EPostConditionViolation )); + } + +/** +* MacSetSinkSampleRateL +* @param aSampleRate +*/ +void CMMFAudioController::MacSetSinkSampleRateL(TUint aSampleRate) + { + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic( EBadStateToSetSinkSampleRate)); + + // [ assert the precondition that we are stopped ] + if (State() != EStopped ) + User::Leave(KErrNotReady); + + if (iSinkFormat) + {//only applicable to formats + // don't throw an error if the clip already exists with a different sample rate + TInt error = iSinkFormat->SetSampleRate(aSampleRate); + if (error != KErrNone && error != KErrAlreadyExists) + User::Leave(error); + } + else + {//during playing, sample rate cannot be set directly on the datasink. It is set via NegotiateL + User::Leave(KErrNotSupported); + } + + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic( EBadStateAfterSetSinkSampleRate)); + } + +/** +* MacSetSinkNumChannelsL +* @param aNumChannels +* +*/ +void CMMFAudioController::MacSetSinkNumChannelsL(TUint aNumChannels) + { + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic( EBadStateToSetSinkNumChannels)); + + // [ assert the precondition that we are stopped ] + if (State() != EStopped ) + User::Leave(KErrNotReady); + + if (iSinkFormat) + {//only applicable to formats + // don't throw an error if the clip already exists with a different number of channels + TInt error = iSinkFormat->SetNumChannels(aNumChannels); + if (error != KErrNone && error != KErrAlreadyExists) + User::Leave(error); + } + else + {//during playing, channels cannot be set directly on the datasink. It is set via NegotiateL + User::Leave(KErrNotSupported); + } + + // [assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic( EBadStateAfterSetSinkNumChannels)); + + } + +/** +* MacSetSinkFormatL +* @param aFormatUid +* +*/ +void CMMFAudioController::MacSetSinkFormatL(TUid aFormatUid) + { + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic( EBadStateToSetSinkFormat)); + + // [ precondition that the controller is stopped ] + if( State() != EStopped ) + User::Leave( KErrNotReady ); + + //[ precondition that the data sink exists] + if (!iDataSink) + User::Leave(KErrNotReady); + + //[ precondition that we need a format ] + if (!SinkFormatRequired( *iDataSink)) + User::Leave(KErrNotSupported); + + //[ if the format exists and the uid of the requested + // format is the same as the existing format then simply + // return ] + if( !((iSinkFormat) && ( iSinkFormat->ImplementationUid() == aFormatUid))) + { + // [ delete the old format regardless ] + delete iSinkFormat; + iSinkFormat = NULL; + iSinkFormat = CMMFFormatEncode::NewL(aFormatUid, iDataSink); + } + + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic( EBadStateAfterSetSinkFormat)); + + //[ assert the post condition that a sink format has been constructed ] + __ASSERT_ALWAYS( (iSinkFormat != NULL), Panic( EPostConditionViolation )); + } + + +/** +* MacSetCodecL +* @param aSourceDataType +* @param aSinkDataType +* +*/ +void CMMFAudioController::MacSetCodecL(TFourCC aSourceDataType, TFourCC aSinkDataType) + { + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic(EBadStateToSetCodec)); + + //[ assert the precondition ] + if(State() != EStopped) + User::Leave(KErrNotReady); + + //pre condition that we have a source format or sink format + if (!iSourceFormat && !iSinkFormat) + { + User::Leave(KErrNotSupported); + } + //don't set codec directly -just set source & sink fourCC codes + //[ ] + TInt error(KErrNone); + if ((iSinkFormat)&&(aSinkDataType != KMMFFourCCCodeNULL)) + { + error = iSinkFormat->SetSinkDataTypeCode(aSinkDataType,iMediaId); + } + if ((iSourceFormat)&&(!error)&&(aSourceDataType != KMMFFourCCCodeNULL)) + { + error = iSourceFormat->SetSourceDataTypeCode(aSourceDataType,iMediaId); + } + + //[ leave if we are not ready or there was an error ] + User::LeaveIfError(error); + + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic(EBadStateAfterSetCodec)); + } + +/** +* MacSetSourceBitRateL +* @param "TUint" +* Sets the source bit rate +* +*/ +void CMMFAudioController::MacSetSourceBitRateL(TUint aBitRate) + { + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic(EBadStateToSetSourceBitRate)); + + //[ assert the precondition ] + if(State() != EStopped) + User::Leave(KErrNotReady); + + //[ pre condition that we have a source format] + if (!iSourceFormat) + User::Leave(KErrNotSupported); + + //only applicable to formats + User::LeaveIfError(iSourceFormat->SetBitRate(aBitRate)); + + //[ assert the set bit rate is the bit rate ] + __ASSERT_ALWAYS( (aBitRate == iSourceFormat->BitRate()), Panic( EPostConditionViolation )); + + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic( EBadStateAfterSetSourceBitRate)); + } + + +/** +* +* MacSetSourceDataTypeL +* @param "TFourCC" +* +*/ +void CMMFAudioController::MacSetSourceDataTypeL(TFourCC aDataType) + { + //pre condition we have a source format + if (!iSourceFormat) + { + User::Leave(KErrNotSupported); + } + + MacSetCodecL(aDataType, KMMFFourCCCodeNULL); + } + +/** +* +* MacSetSinkBitRateL +* @param "TUint" +* +*/ +void CMMFAudioController::MacSetSinkBitRateL(TUint aRate) + { + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic( EBadStateToSetSinkBitRate)); + + // [ assert we are stopped ] + if( State() != EStopped) + User::Leave( KErrNotReady ); + + //[ pre condition we have a sink format ] + if (!iSinkFormat) + User::Leave(KErrNotSupported); + + //only applicable to formats + User::LeaveIfError(iSinkFormat->SetBitRate(aRate)); + + //[ assert the set bit rate is the bit rate ] + __ASSERT_ALWAYS( (aRate == iSinkFormat->BitRate()), Panic( ESetRateIsNotSameAsBitRate)); + + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic( EBadStateAfterSetSinkBitRate)); + } + +/** +* +* MacSetSinkDataTypeL +* @param "TFourCC" +* +*/ +void CMMFAudioController::MacSetSinkDataTypeL(TFourCC aDataType) + { + //precondition is that we have a sink format + if (!iSinkFormat) + { + User::Leave(KErrNotSupported); + } + + MacSetCodecL(KMMFFourCCCodeNULL, aDataType); + } + +/** +* +* MacGetSourceSampleRateL +* @param "TUint" +* +*/ +void CMMFAudioController::MacGetSourceSampleRateL(TUint& aRate) + { + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic( EBadStateToGetSourceSampleRate)); + + //precondition is that we have a source format + if (!iSourceFormat) + { + User::Leave(KErrNotSupported); + } + + aRate = iSourceFormat->SampleRate(); + + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic( EBadStateAfterGetSourceSampleRate)); + } + +/** +* +* MacGetSourceBitRateL +* @param "TUint" +* +*/ +void CMMFAudioController::MacGetSourceBitRateL(TUint& aRate) + { + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic( EBadStateToGetSourceBitRate)); + + // Can only query formats for bit rate - devsound doesn't do bit rates. + if (!iSourceFormat) + User::Leave(KErrNotSupported); + + aRate = iSourceFormat->BitRate(); + + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic( EBadStateToGetSourceBitRate)); + + } + +/** +* +* MacGetSourceNumChannelsL +* @param "TUint&" +* +*/ +void CMMFAudioController::MacGetSourceNumChannelsL(TUint& aNumChannels) + { + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic( EBadStateToGetSourceNumChannels)); + + //precondition is that we have a source format + if (!iSourceFormat) + { + User::Leave(KErrNotSupported); + } + + aNumChannels = iSourceFormat->NumChannels(); + + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic( EBadStateAfterGetSourceNumChannels)); + + } + +/** +* +* MacGetSourceFormatL +* @param "TUid" +*/ +void CMMFAudioController::MacGetSourceFormatL(TUid& aFormat) + { + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic( EBadStateToGetSourceFormat)); + + //[ precondition we have a format ] + if (!iSourceFormat) + User::Leave(KErrNotSupported); + + // [ get the source format uid ] + aFormat = iSourceFormat->ImplementationUid(); + + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic( EBadStateAfterGetSourceFormat)); + + } + +/** +* +* MacGetSourceDataTypeL +* @param "TFourCC&" +* +*/ +void CMMFAudioController::MacGetSourceDataTypeL(TFourCC& aDataType) + { + //precondition is that we have a source format + if (!iSourceFormat) + { + User::Leave(KErrNotSupported); + } + + aDataType = iSourceFormat->SourceDataTypeCode(TMediaId(KUidMediaTypeAudio)); + } + +/** +* +* MacGetSinkSampleRateL +* @param "TUint&" +* +*/ + +void CMMFAudioController::MacGetSinkSampleRateL(TUint& aRate) + { + //precondition is that we have a sink format + if (!iSinkFormat) + { + User::Leave(KErrNotSupported); + } + + aRate = iSinkFormat->SampleRate(); + } + +/** +* +* MacGetSinkBitRateL +* @param "TUint&" +* +*/ +void CMMFAudioController::MacGetSinkBitRateL(TUint& aRate) + { + if (iSinkFormat) + aRate = iSinkFormat->BitRate(); + else + User::Leave(KErrNotSupported); + } + +/** +* +* MacGetSinkNumChannelsL +* @param "TUint&" +* +*/ +void CMMFAudioController::MacGetSinkNumChannelsL(TUint& aNumChannels) + { + //precondition is that we have a sink format + if (!iSinkFormat) + { + User::Leave(KErrNotSupported); + } + + aNumChannels = iSinkFormat->NumChannels(); + } + +/** +* +* MacGetSinkFormatL +* @param "TUid&" +* +*/ +void CMMFAudioController::MacGetSinkFormatL(TUid& aFormat) + { + if (iSinkFormat) + aFormat = iSinkFormat->ImplementationUid(); + else + User::Leave(KErrNotSupported); + } + +/** +* +* MacGetSinkDataTypeL +* @param "TFourCC&" +* +*/ +void CMMFAudioController::MacGetSinkDataTypeL(TFourCC& aDataType) + { + //precondition is that we have a sink format + if (!iSinkFormat) + { + User::Leave(KErrNotSupported); + } + + aDataType = iSinkFormat->SinkDataTypeCode(TMediaId(KUidMediaTypeAudio)); + } + +/** +* +* MacGetSupportedSourceSampleRatesL +* @param "RArray&" +* +*/ +void CMMFAudioController::MacGetSupportedSourceSampleRatesL(RArray& aSupportedRates) + { + //precondition is that we have a source format + if (!iSourceFormat) + { + User::Leave(KErrNotSupported); + } + + aSupportedRates.Reset(); + iSourceFormat->GetSupportedSampleRatesL(aSupportedRates); + } + +/** +* +* MacGetSupportedSourceBitRatesL +* @param "RArray&" +* +*/ +void CMMFAudioController::MacGetSupportedSourceBitRatesL(RArray& aSupportedRates) + { + aSupportedRates.Reset(); + if (iSourceFormat) + iSourceFormat->GetSupportedBitRatesL(aSupportedRates); + else + User::Leave(KErrNotSupported); + } + +/*** +* +* MacGetSupportedSourceNumChannelsL +* @param "RArray&" +* +*/ +void CMMFAudioController::MacGetSupportedSourceNumChannelsL(RArray& aSupportedChannels) + { + //precondition is that we have a source format + if (!iSourceFormat) + { + User::Leave(KErrNotSupported); + } + + aSupportedChannels.Reset(); + iSourceFormat->GetSupportedNumChannelsL(aSupportedChannels); + } + +/*** +* +* MacGetSupportedSourceDataTypesL +* @param "RArray&" +* +*/ +void CMMFAudioController::MacGetSupportedSourceDataTypesL(RArray& aSupportedDataTypes) + { + //precondition is that we have a source format + if (!iSourceFormat) + { + User::Leave(KErrNotSupported); + } + + aSupportedDataTypes.Reset(); + iSourceFormat->GetSupportedDataTypesL(TMediaId(KUidMediaTypeAudio), aSupportedDataTypes); + } + +/*** +* +* MacGetSupportedSinkSampleRatesL +* @param "RArray& " +* +*/ +void CMMFAudioController::MacGetSupportedSinkSampleRatesL(RArray& aSupportedRates) + { + //precondition is that we have a sink format + if (!iSinkFormat) + { + User::Leave(KErrNotSupported); + } + + aSupportedRates.Reset(); + iSinkFormat->GetSupportedSampleRatesL(aSupportedRates); + } + +/*** +* +* MacGetSupportedSinkBitRatesL +* @param RArray& +* +*/ +void CMMFAudioController::MacGetSupportedSinkBitRatesL(RArray& aSupportedRates) + { + if (iSinkFormat) + iSinkFormat->GetSupportedBitRatesL(aSupportedRates); + else + User::Leave(KErrNotSupported); + } + +/*** +* +* MacGetSupportedSinkNumChannelsL +* @param RArray& +* +*/ +void CMMFAudioController::MacGetSupportedSinkNumChannelsL(RArray& aSupportedChannels) + { + //precondition is that we have a sink format + if (!iSinkFormat) + { + User::Leave(KErrNotSupported); + } + + aSupportedChannels.Reset(); + iSinkFormat->GetSupportedNumChannelsL(aSupportedChannels); + } + +/*** +* +* MacGetSupportedSinkDataTypesL +* @param "RArray&" +*/ +void CMMFAudioController::MacGetSupportedSinkDataTypesL(RArray& aSupportedDataTypes) + { + //precondition is that we have a sink format + if (!iSinkFormat) + { + User::Leave(KErrNotSupported); + } + + aSupportedDataTypes.Reset(); + iSinkFormat->GetSupportedDataTypesL(TMediaId(KUidMediaTypeAudio), aSupportedDataTypes); + } + +/** +* +* ConvertFromDevSoundCapsToSampleRatesL +* @param "const TMMFCapabilities& " +* @param "RArray&" +* +*/ +void CMMFAudioController::ConvertFromDevSoundCapsToSampleRatesL(const TMMFCapabilities& aDevSoundCaps, RArray& aSampleRates) + { + if (aDevSoundCaps.iRate & EMMFSampleRate8000Hz) + User::LeaveIfError(aSampleRates.Append(KSampleRate8000Hz)); + if (aDevSoundCaps.iRate & EMMFSampleRate11025Hz) + User::LeaveIfError(aSampleRates.Append(KSampleRate11025Hz)); + if (aDevSoundCaps.iRate & EMMFSampleRate12000Hz) + User::LeaveIfError(aSampleRates.Append(KSampleRate12000Hz)); + if (aDevSoundCaps.iRate & EMMFSampleRate16000Hz) + User::LeaveIfError(aSampleRates.Append(KSampleRate16000Hz)); + if (aDevSoundCaps.iRate & EMMFSampleRate22050Hz) + User::LeaveIfError(aSampleRates.Append(KSampleRate22050Hz)); + if (aDevSoundCaps.iRate & EMMFSampleRate24000Hz) + User::LeaveIfError(aSampleRates.Append(KSampleRate24000Hz)); + if (aDevSoundCaps.iRate & EMMFSampleRate32000Hz) + User::LeaveIfError(aSampleRates.Append(KSampleRate32000Hz)); + if (aDevSoundCaps.iRate & EMMFSampleRate44100Hz) + User::LeaveIfError(aSampleRates.Append(KSampleRate44100Hz)); + if (aDevSoundCaps.iRate & EMMFSampleRate48000Hz) + User::LeaveIfError(aSampleRates.Append(KSampleRate48000Hz)); + if (aDevSoundCaps.iRate & EMMFSampleRate64000Hz) + User::LeaveIfError(aSampleRates.Append(KSampleRate64000Hz)); + if (aDevSoundCaps.iRate & EMMFSampleRate88200Hz) + User::LeaveIfError(aSampleRates.Append(KSampleRate88200Hz)); + if (aDevSoundCaps.iRate & EMMFSampleRate96000Hz) + User::LeaveIfError(aSampleRates.Append(KSampleRate96000Hz)); + } + +/** +* +* ConvertFromDevSoundCapsToNumChannelsL +* @param "const TMMFCapabilities&" +* @param "RArray&" +* +*/ +void CMMFAudioController::ConvertFromDevSoundCapsToNumChannelsL(const TMMFCapabilities& aDevSoundCaps, RArray& aNumChannels) + { + if (aDevSoundCaps.iChannels & EMMFMono) + User::LeaveIfError(aNumChannels.Append(KNumChannelsMono)); + if (aDevSoundCaps.iChannels & EMMFStereo) + User::LeaveIfError(aNumChannels.Append(KNumChannelsStereo)); + } + +/** +* +* ConvertFromDevSoundCapsToDataTypesL +* @param "const TMMFCapabilities&" +* @param "TMMFCapabilities& aDevSoundCaps, RArray&" +* +*/ +void CMMFAudioController::ConvertFromDevSoundCapsToDataTypesL(const TMMFCapabilities& aDevSoundCaps, RArray& aDataTypes) + { + if (aDevSoundCaps.iEncoding & EMMFSoundEncoding8BitPCM) + User::LeaveIfError(aDataTypes.Append(KMMFFourCCCodePCM8)); + if (aDevSoundCaps.iEncoding & EMMFSoundEncoding16BitPCM) + User::LeaveIfError(aDataTypes.Append(KMMFFourCCCodePCM16)); + if (aDevSoundCaps.iEncoding & EMMFSoundEncoding8BitALaw) + User::LeaveIfError(aDataTypes.Append(KMMFFourCCCodeALAW)); + if (aDevSoundCaps.iEncoding & EMMFSoundEncoding8BitMuLaw) + User::LeaveIfError(aDataTypes.Append(KMMFFourCCCodeMuLAW)); + } + +/** +* +* ConvertFromSampleRateToDevSoundCapsL +* @param "TUint" +* @param "TMMFCapabilities&" +* +*/ +void CMMFAudioController::ConvertFromSampleRateToDevSoundCapsL(TUint aSampleRate, TMMFCapabilities& aDevSoundCaps) + { + if (aSampleRate == KSampleRate8000Hz) + aDevSoundCaps.iRate = EMMFSampleRate8000Hz; + else if (aSampleRate == KSampleRate11025Hz) + aDevSoundCaps.iRate = EMMFSampleRate11025Hz; + else if (aSampleRate == KSampleRate12000Hz) + aDevSoundCaps.iRate = EMMFSampleRate12000Hz; + else if (aSampleRate == KSampleRate16000Hz) + aDevSoundCaps.iRate = EMMFSampleRate16000Hz; + else if (aSampleRate == KSampleRate22050Hz) + aDevSoundCaps.iRate = EMMFSampleRate22050Hz; + else if (aSampleRate == KSampleRate24000Hz) + aDevSoundCaps.iRate = EMMFSampleRate24000Hz; + else if (aSampleRate == KSampleRate32000Hz) + aDevSoundCaps.iRate = EMMFSampleRate32000Hz; + else if (aSampleRate == KSampleRate44100Hz) + aDevSoundCaps.iRate = EMMFSampleRate44100Hz; + else if (aSampleRate == KSampleRate48000Hz) + aDevSoundCaps.iRate = EMMFSampleRate48000Hz; + else if (aSampleRate == KSampleRate64000Hz) + aDevSoundCaps.iRate = EMMFSampleRate64000Hz; + else if (aSampleRate == KSampleRate88200Hz) + aDevSoundCaps.iRate = EMMFSampleRate88200Hz; + else if (aSampleRate == KSampleRate96000Hz) + aDevSoundCaps.iRate = EMMFSampleRate96000Hz; + else + User::Leave(KErrNotSupported); + } + +/** +* +* ConvertFromNumChannelsToDevSoundCapsL +* @param "TUint" +* @param "TMMFCapabilities&" +* +*/ +void CMMFAudioController::ConvertFromNumChannelsToDevSoundCapsL(TUint aNumChannels, TMMFCapabilities& aDevSoundCaps) + { + if (aNumChannels == KNumChannelsMono) + aDevSoundCaps.iChannels = EMMFMono; + else if (aNumChannels == KNumChannelsStereo) + aDevSoundCaps.iChannels = EMMFStereo; + else + User::Leave(KErrNotSupported); + } + +/** +* +* ConvertFromDataTypeToDevSoundCapsL +* @param "TFourCC" +* @param "TMMFCapabilities&" +* +*/ +void CMMFAudioController::ConvertFromDataTypeToDevSoundCapsL(TFourCC aDataType, TMMFCapabilities& aDevSoundCaps) + { + if (aDataType == KMMFFourCCCodePCM8) + aDevSoundCaps.iEncoding = EMMFSoundEncoding8BitPCM; + else if (aDataType == KMMFFourCCCodePCM16) + aDevSoundCaps.iEncoding = EMMFSoundEncoding16BitPCM; + else if (aDataType == KMMFFourCCCodeALAW) + aDevSoundCaps.iEncoding = EMMFSoundEncoding8BitALaw; + else if (aDataType == KMMFFourCCCodeMuLAW) + aDevSoundCaps.iEncoding = EMMFSoundEncoding8BitMuLaw; + else + User::Leave(KErrNotSupported); + } + +/** +* IsValidStateTransition +* The function validates a state transition from iState to aState +* and returns ETrue if the transition is allowed. +* @internalTechnology +* @param TControllerState +* @returns "TBool" +*/ +TBool CMMFAudioController::IsValidStateTransition( TControllerState aState ) const + { + TBool result = ETrue ; + //[ assert the precondition that aState is a valid State ] + __ASSERT_ALWAYS( IsValidState(aState), Panic( EBadArgument ) ); + //[ assert the invariant that iState is a valid State ] + __ASSERT_ALWAYS( Invariant(), Panic( EInvalidState )); + + // [ check the valid state transitions ] + // the only invalid transition is + // stopped to playing + if( ( iState == EStopped ) && ( aState == EPlaying )) + { + result = EFalse ; + } + + //[ assert the invariant that iState is a valid State ] + __ASSERT_ALWAYS( Invariant(), Panic( EInvalidState )); + + return result ; + } + +/* +* Invariant +* @internalTechnology +* @returns "TBool" +* This function returns whether the invariant is valid +*/ +TBool CMMFAudioController::Invariant() const + { + //[ The invariant is for now defined + // as simply being in the correct state and + // having iDataPath defined ] + return ( iDataPath )&& IsValidState( iState); + } + +/* +* SetState +* This function sets the state of the controller. +* @internalTechnology +* @returns "TBool" +*/ +TBool CMMFAudioController::SetState(TControllerState aState) + { + TBool result = ETrue; + //[ assert the precondition that the state is a valid state ] + __ASSERT_ALWAYS( IsValidState( aState), Panic( EBadArgument ) ); + //[ assert the invariant the current state is valid ] + __ASSERT_ALWAYS( Invariant(), Panic( EBadState ) ); + //[ only allow valid state transitions ] + if( IsValidStateTransition( aState ) ) + { + //[ valid state transition set the state] + iState = aState ; + } + else + { + //[ invalid state transition return EFalse ] + result = EFalse; + } + // [ assert the invariant on the state ] + __ASSERT_ALWAYS( Invariant(), Panic( EBadState )); + + return result ; + } + +/* +* IsValidState +* checks whether a state is a valid +* @internalTechnology +* @returns "TBool" +* @param TControllerState +*/ +TBool CMMFAudioController::IsValidState( TControllerState aState ) const + { + TBool result = EFalse; + if(( aState >= EStopped ) && ( aState <= EPlaying )) + { + result = ETrue; + } + return result; + } + +/** +* State +* The function State returns the current state of the audio controller +* @internalTechnology +* @returns "TControllerState" +*/ +CMMFAudioController::TControllerState CMMFAudioController::State() const + { + __ASSERT_ALWAYS( Invariant(), Panic( EBadState ) ); + return iState; + } + +/** +* +* SinkFormatRequired +* +*/ +TBool CMMFAudioController::SinkFormatRequired( MDataSink& aDataSink ) const + { + return (aDataSink.DataSinkType()==KUidMmfFileSink || + aDataSink.DataSinkType()==KUidMmfDescriptorSink); + } + +/** +* +* SourceFormatRequired +* +*/ + +TBool CMMFAudioController::SourceFormatRequired(MDataSource& aDataSource) const + { + return (aDataSource.DataSourceType()==KUidMmfFileSource || + aDataSource.DataSourceType()==KUidMmfDescriptorSource); + } + +TInt CMMFAudioController::MdcEvaluateIntent(ContentAccess::TIntent aIntent) + { + if (iDataSource->DataSourceType()==KUidMmfFileSource) + { + CMMFFile* file = static_cast(iDataSource); + TInt err = file->EvaluateIntent(aIntent); + return err; + } + else + { + // Evaluating intent will always succeed on sinks that + // don't support DRM + return KErrNone; + } + + } + +TInt CMMFAudioController::MdcExecuteIntent(ContentAccess::TIntent aIntent) + { + if (iDataSource->DataSourceType()==KUidMmfFileSource) + { + CMMFFile* file = static_cast(iDataSource); + TInt err = file->ExecuteIntent(aIntent); + return err; + } + else + { + // Executing intent will always succeed on sinks that + // don't support DRM + return KErrNone; + } + } + +TInt CMMFAudioController::MdcDisableAutomaticIntent(TBool aDisableAutoIntent) + { + iDisableAutoIntent = aDisableAutoIntent; + return KErrNone; + } + + +TInt CMMFAudioController::MdcSetAgentProperty(ContentAccess::TAgentProperty aProperty, TInt aValue) + { + if (iDataSource->DataSourceType()==KUidMmfFileSource) + { + CMMFFile* file = static_cast(iDataSource); + TInt err = file->SetAgentProperty(aProperty, aValue); + return err; + } + else + { + return KErrNone; + } + } + +void CMMFAudioController::MarnRegisterAsClientL(TUid aEventType,const TDesC8& aNotificationRegistrationData) + { + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic(EBadStateToRegisterAsClient)); + //[ precondition that we have a sink] + if (!iDataSink) + { + User::Leave(KErrNotReady); + } + //[register the notification ] + MMMFAudioOutput* audioOutput = static_cast(iDataSink); + TInt err = audioOutput->SoundDevice().RegisterAsClient(aEventType, aNotificationRegistrationData); + User::LeaveIfError(err); + iRegisterARN = ETrue; + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic(EBadStateAfterRegisterAsClient)); + } + +void CMMFAudioController::MarnCancelRegisterAsClientL(TUid aEventType) + { + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic(EBadStateToCancelRegisterAsClient)); + //[ precondition that we have a sink] + if (!iDataSink) + { + User::Leave(KErrNotReady); + } + //[cancel the notification ] + MMMFAudioOutput* audioOutput = static_cast(iDataSink); + TInt err = audioOutput->SoundDevice().CancelRegisterAsClient(aEventType); + User::LeaveIfError(err); + iRegisterARN = EFalse; + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic(EBadStateAfterCancelRegisterAsClient)); + } + +void CMMFAudioController::MarnGetResourceNotificationDataL(TUid aEventType,TDes8& aNotificationData) + { + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic(EBadStateToGetResourceNotificationData)); + //[ precondition that we have a sink] + if (!iDataSink) + { + User::Leave(KErrNotReady); + } + //[get the notification data] + MMMFAudioOutput* audioOutput = static_cast(iDataSink); + TMMFTimeIntervalMicroSecondsPckg pckg; + TInt err = audioOutput->SoundDevice().GetResourceNotificationData(aEventType, pckg); + User::LeaveIfError(err); + + // aNotificationData is a package buffer returned as TMMFTimeIntervalMicroSecondsPckg, + // but the contents should be converted to an integer and interpreted as the + // data returned is samples played, but not as a microsecond value. + // As the client expects a position (in microseconds from the beginning + // of the clip) we need to convert the data depending on the sample rate + // Potential issue if using the number of samples played with VBR sampling. + RArray array; + CleanupClosePushL(array); + ConvertFromDevSoundCapsToSampleRatesL(audioOutput->SoundDevice().Config(), array); + // Should only ever have 1 entry in the array + ASSERT(array.Count() == 1); + TUint rate = array[0]; + if (rate) + { + // Convert the given number of samples using the sample rate + const TInt KMicroSecsInOneSec = 1000000; + TTimeIntervalMicroSeconds value = pckg(); + value = TTimeIntervalMicroSeconds(value.Int64() * KMicroSecsInOneSec / rate); + pckg() = value; + } + else + { + User::Leave(KErrArgument); + } + aNotificationData = pckg; + CleanupStack::PopAndDestroy();//array + + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic(EBadStateAfterGetResourceNotificationData)); + } + +void CMMFAudioController::MarnWillResumePlayL() + { + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic(EBadStateToResumePlay)); + //[ precondition that we have a sink] + if (!iDataSink) + { + User::Leave(KErrNotReady); + } + //[wait for the client to resume ] + MMMFAudioOutput* audioOutput = static_cast(iDataSink); + TInt err = audioOutput->SoundDevice().WillResumePlay(); + User::LeaveIfError(err); + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic(EBadStateAfterResumePlay)); + }