diff -r 000000000000 -r 71ca22bcf22a mmfenh/advancedaudiocontroller/wavplaycontrollerplugin/src/MmfAudioController.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mmfenh/advancedaudiocontroller/wavplaycontrollerplugin/src/MmfAudioController.cpp Tue Feb 02 01:08:46 2010 +0200 @@ -0,0 +1,3270 @@ +/* +* Copyright (c) 2005-2006 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 "mmffile.h" +#include +#include "devsoundstandardcustominterfaces.h" +#include "CustomInterfaceBuilder.h" +#include "CustomInterfaceCustomCommandParser.h" +#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 + }; + +/** +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; + iStoppingPlaying = 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); + +#ifdef SYMBIAN_CAF_V2 + CMMFDRMCustomCommandParser* drmParser = CMMFDRMCustomCommandParser::NewL(*this); + CleanupStack::PushL(drmParser); + AddCustomCommandParserL(*drmParser); + CleanupStack::Pop(drmParser); +#endif + + CMMFResourceNotificationCustomCommandParser* NotiParser = CMMFResourceNotificationCustomCommandParser::NewL(*this); + CleanupStack::PushL(NotiParser); + AddCustomCommandParserL(*NotiParser); + CleanupStack::Pop(NotiParser);//audio resource Notification Parser + + CCustomInterfaceCustomCommandParser* customInterfaceParser = CCustomInterfaceCustomCommandParser::NewL(*this); + CleanupStack::PushL(customInterfaceParser); + AddCustomCommandParserL(*customInterfaceParser); + CleanupStack::Pop(customInterfaceParser); + + CMMFAudioPlayControllerSetRepeatsCustomCommandParser* audPlayConSetRepeatsParser = CMMFAudioPlayControllerSetRepeatsCustomCommandParser::NewL(*this); + CleanupStack::PushL(audPlayConSetRepeatsParser); + AddCustomCommandParserL(*audPlayConSetRepeatsParser); + CleanupStack::Pop(audPlayConSetRepeatsParser); + + TInt err = CConfigurationComponentsFactory::CreateFactoryL(iFactory); + User::LeaveIfError(err); + + if (iFactory) + { + err = iFactory->CreateAudioOutputControlUtility(iAudioOutputControlUtility); + User::LeaveIfError(err); + } + // [ assert the invariant now that we are constructed ] + __ASSERT_ALWAYS( Invariant(), Panic( EBadInvariant)); + } + +/** +* +* CMMFAudioController +* +*/ + +CMMFAudioController::CMMFAudioController() + : iMediaId(KUidMediaTypeAudio), + iDisableAutoIntent(EFalse), + iState(EStopped) + { + } + +/** +* +* ~CMMFAudioController +* +*/ + +CMMFAudioController::~CMMFAudioController() + { + // [ ensure we have logged off the thread ] + if(iAudioOutputControlUtility) + delete iAudioOutputControlUtility; + if(iFactory) + delete iFactory; + if( iDataPath ) + { + TRAP_IGNORE(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( EBadInvariant)); + + // [ 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(EBadInvariant)); + // [ lets load dev sound ] + User::LeaveIfError(audioInput->SourceThreadLogon( *this )); + } + else + { + User::Leave(KErrNotSupported); + } + + //[ its now safe to set the source ] + iDataSource = &aSource ; + iDataSource->SetSourcePrioritySettings(iPrioritySettings); + + //[ assert the post condition ] + __ASSERT_ALWAYS(iDataSource, Panic(EMMFAudioControllerPanicDataSourceDoesNotExist)); + + } + + +/** + * AddDataSinkL + * + * Adds a data sink to the controller + * + * @param aSink + * + */ +void CMMFAudioController::AddDataSinkL(MDataSink& aSink) + { + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic( EBadInvariant)); + + // [ 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(EBadInvariant)); + // [ lets load dev sound ] + User::LeaveIfError(audioOutput->SinkThreadLogon( *this )); + 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; + iDataSink->SetSinkPrioritySettings(iPrioritySettings); + + // [ assert post conditions that a sink has been added ] + __ASSERT_ALWAYS(iDataSink, Panic(EMMFAudioControllerPanicDataSinkDoesNotExist)); + + } + +/** + * 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( EBadInvariant)); + + //[ 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( EBadInvariant)); + __ASSERT_ALWAYS( iDataSink, Panic( EBadInvariant)); + + + //[ 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(); + + //********** Symbian Change. + //TInt err = KErrNotSupported; + //if (iSinkFormat) + // { + // err = iDataPath->SetBlockLength(blockLength); + // } + //************ + 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 (file->IsProtectedL()) + { + if (iDataSink->DataSinkType()!=KUidMmfAudioOutput) + { + User::Leave(KErrNotSupported); + } + TInt err; + err = iAudioOutputControlUtility->SetDataSource(iDataSource); + if (err != KErrNone) + { + User::Leave(err); + } + } + } + + //[ assert the post condition that we are in the state primed] + __ASSERT_ALWAYS( SetState( EPrimed ), Panic( EPostConditionViolation )); + // [ assert the invariant] + __ASSERT_ALWAYS( Invariant(), Panic( EBadInvariant ) ); + } + +/** + * ResetL + * This method resets the controller + * + */ +void CMMFAudioController::ResetL() + { + __ASSERT_ALWAYS( Invariant(), Panic( EBadInvariant ) ); + + // 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( EBadInvariant ) ); + + // [ 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(EBadInvariant)); + + // 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 + // In case of system preemption (like audio is preempted by voice call)ExecuteIntent should not be called. + 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] + if(iIsPaused) + { + iDataPath->RetainRepeatInfo(); + } + + //configure Devsound with output restriction for a DRM protected file + if (iDataSource->DataSourceType()==KUidMmfFileSource) + { + CMMFFile* file = static_cast(iDataSource); + // we only support protected files for playback + if (file->IsProtectedL()) + { + MMMFAudioOutput* audioOutput = static_cast(iDataSink); + iAudioOutputControlUtility->Configure(audioOutput->SoundDevice()); //ignoring errors since rouitng changes are only suggestions to adaptation + } + } + 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(EBadInvariant)); + } + +/** + * PauseL + * + */ +void CMMFAudioController::PauseL() + { + // [ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic(EBadInvariant)); + + //[ assert the precondition that we are playing ] + if ( State() != EPlaying) + { + User::Leave(KErrNotReady); + } + // In case of system preemption (like audio is preempted by voice call)ExecuteIntent should not be called. + 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(EBadInvariant)); + } + +/** + * StopL + * + */ +void CMMFAudioController::StopL(TMMFMessage& aMessage) + { + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic(EBadInvariant)); + // [ 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 && !iStoppingPlaying) + { + 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 + iStoppingPlaying = ETrue; + iDataPath->Stop(); + SetState(EStopped); + iStoppingPlaying = EFalse; + } + } + iIsPaused = EFalse; + iIsPreemptionPause = EFalse; + //complete message as request is complete. + if(State() == EStopped && !IsUnderTest()) + { + aMessage.Complete(KErrNone); + } + + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic(EBadInvariant)); + } + +/** + * PositionL + * Preconditions: + * The Controller is in the state EPrimed + * @return TTimeIntervalMicroSeconds + * + */ +TTimeIntervalMicroSeconds CMMFAudioController::PositionL() const + { + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic(EBadInvariant)); + // [ precondition that we are playing or primed ] + if( !((State() == EPrimed) || (State() == EPlaying))) + User::Leave(KErrNotReady); + + TTimeIntervalMicroSeconds position = iDataPath->Position(); + + if ((State() == EPlaying) && (iDataSource->DataSourceType()==KUidMmfAudioInput)) + position = DurationL(); + + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic(EBadInvariant)); + + return position; + } + +/** +* SetPositionL +* +* @param aPosition +* +*/ +void CMMFAudioController::SetPositionL(const TTimeIntervalMicroSeconds& aPosition) + { + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic(EBadInvariant)); + + // [ 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(); + 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(EBadInvariant)); + + // [ 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(EBadInvariant)); + + + // [ 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(EBadInvariant)); + + return theDuration; + } + +/** +* +* GetNumberOfMetaDataEntriesL +* +* @param "TInt" +* +*/ +void CMMFAudioController::GetNumberOfMetaDataEntriesL(TInt& aNumberOfEntries ) + { + + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic(EBadInvariant)); + + //[ 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(EBadInvariant)); + + } + +/** +* GetMetaDataEntryL +* @param aIndex +* @returns "CMMFMetaDataEntry*" +*/ +CMMFMetaDataEntry* CMMFAudioController::GetMetaDataEntryL(TInt aIndex ) + { + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic(EBadInvariant)); + + //[ 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(EBadInvariant)); + + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic(EBadInvariant)); + + return theEntry; + } + +/** +* RemoveDataSourceL +* @param aDataSource +* +*/ +void CMMFAudioController::RemoveDataSourceL(MDataSource& aDataSource ) + { + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic(EBadInvariant) ); + + //[ 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(EBadInvariant)); + + } + +/** +* RemoveDataSinkL +* +* @param aDataSink +* +*/ +void CMMFAudioController::RemoveDataSinkL(MDataSink& aDataSink ) + { + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic(EBadInvariant) ); + + //[ 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(EBadInvariant)); + } + +/** + * CustomCommand + * @param aMessage + */ +void CMMFAudioController::CustomCommand(TMMFMessage& aMessage) + { + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic(EBadInvariant)); + // [ We do not have any custom commands ] + aMessage.Complete(KErrNotSupported); + } + +/** +* NegotiateL +* +*/ +void CMMFAudioController::NegotiateL() + { + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic(EBadInvariant)); + + //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(EBadInvariant)); + } + +/** + * SetPrioritySettings + * + * @param aPrioritySettings + */ +void CMMFAudioController::SetPrioritySettings(const TMMFPrioritySettings& aPrioritySettings) + { + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic(EBadInvariant)); + + //[ 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(EBadInvariant)); + } + +/** + * SendEventToClient + * + * @param aEvent + */ +TInt CMMFAudioController::SendEventToClient(const TMMFEvent& aEvent) + { + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic(EBadInvariant)); + + 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 ); + } + } + + //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) + { + //we don't want to send an event to the client + // if we are already in the process of Stopping + if(iStoppingPlaying) + { + return KErrNone; + } + + //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(EBadInvariant)); + + return result; + } + + +/** +* MapdSetVolumeL +* +* @param aVolume +* +*/ +void CMMFAudioController::MapdSetVolumeL(TInt aVolume) + { + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic(EBadInvariant)); + + // [ 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(EBadInvariant)); + } + +/** +* +* MapdGetMaxVolumeL +* +* @param aMaxVolume +* +*/ +void CMMFAudioController::MapdGetMaxVolumeL(TInt& aMaxVolume) + { + // [ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic(EBadInvariant)); + + //[ 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(EBadInvariant)); + + } + + +/** +* +* MapdGetVolumeL +* +* @param aVolume +* +*/ +void CMMFAudioController::MapdGetVolumeL(TInt& aVolume) + { + // [ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic(EBadInvariant)); + + //[ 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(EBadInvariant)); + + } + +/** +* +* MapdSetVolumeRampL +* +* @param aRampDuration +* +*/ +void CMMFAudioController::MapdSetVolumeRampL(const TTimeIntervalMicroSeconds& aRampDuration) + { + // [ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic(EBadInvariant)); + + //[ 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(EBadInvariant)); + + } + + +/** +* +* MapdSetBalanceL +* +* @param aBalance +* +*/ +void CMMFAudioController::MapdSetBalanceL(TInt aBalance) + { + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic( EBadInvariant)); + + // [ 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( EBadInvariant)); + } + +/** +* 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; + + // [ assert precondition that aBalance is within limits ] + __ASSERT_ALWAYS( !(aBalance < KMMFBalanceMaxLeft || aBalance > KMMFBalanceMaxRight), Panic(EBadArgument)); + + //[ 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(EBadInvariant)); + + //[ 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(EBadInvariant)); + } + +/** +* 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(EBadInvariant)); + + //[ 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(EBadInvariant)); + + } + +/** +* MardGetMaxGainL +* @param aMaxGain +* +*/ +void CMMFAudioController::MardGetMaxGainL(TInt& aMaxGain) + { + // [ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic(EBadInvariant)); + + // [ 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(EBadInvariant)); + + } + +/** +* MardGetGainL +* @param aGain +* +*/ +void CMMFAudioController::MardGetGainL(TInt& aGain) + { + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic(EBadInvariant)); + + // [ 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(EBadInvariant)); + } + + +/** + * + * MardSetBalanceL + * @param aBalance + */ +void CMMFAudioController::MardSetBalanceL(TInt aBalance) + { + // [ assert the invaraiant ] + __ASSERT_ALWAYS( Invariant(), Panic(EBadInvariant)); + + // [ precondition is that we have a data sink ] + if (!iDataSink) + 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( EBadInvariant)); + + } + +/** +* +* MardGetBalanceL +* @param aBalance +* +*/ +void CMMFAudioController::MardGetBalanceL(TInt& aBalance) + { + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic(EBadInvariant)); + + //[ precondition that we have a sink] + if (!iDataSink) + 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(EBadInvariant)); + + } + +/** +* 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; +#ifdef _DEBUG + RDebug::Print(_L("CMMFAudioController::MapcSetRepeats Enter ")); +#endif + if (!iDataSink) + { + err = KErrNotReady; + } + else if (iDataSink->DataSinkType() != KUidMmfAudioOutput) + { + err = KErrNotSupported; + } + else + { + MMMFAudioOutput* audioOutput = static_cast(iDataSink); + if(audioOutput->SoundDevice().QueryIgnoresUnderflow()) + { +#ifdef _DEBUG + RDebug::Print(_L("CMMFAudioController::MapcSetRepeats RepeatCount [%d] TrailingSilence [%d]"),aRepeatNumberOfTimes, aTrailingSilence.Int64()); +#endif + 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(EBadInvariant)); + + //[ 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( EBadInvariant) ); + } + 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(EBadInvariant)); + } + +/** +* 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(EBadInvariant)); + + //[ 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 > -1, as a basic sanity filter + // 0 is the sentinel value which allows a file to grow + // as needed ] + if( aFileSize < 0 ) + 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(EBadInvariant)); + } + +/** +* MarcCropL +* @param aToEnd +*/ +void CMMFAudioController::MarcCropL(TBool aToEnd) + { + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic(EBadInvariant)); + + //[ precondition there is a sink format] + if (!iSinkFormat) + User::Leave(KErrNotSupported); + + iSinkFormat->CropL( PositionL(), aToEnd ); + + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic(EBadInvariant)); + } + +/** +* MarcAddMetaDataEntryL +* @param aNewEntry +*/ +void CMMFAudioController::MarcAddMetaDataEntryL(const CMMFMetaDataEntry& aNewEntry ) + { + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic(EBadInvariant)); + + //[ precondition the format exists ] + if( !iSinkFormat ) + User::Leave(KErrNotSupported); + + //[ Add the meta data entry ] + iSinkFormat->AddMetaDataEntryL( aNewEntry ); + + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic(EBadInvariant)); + + } + +/** +* MarcRemoveMetaDataEntryL +* @param aIndex +*/ +void CMMFAudioController::MarcRemoveMetaDataEntryL(TInt aIndex) + { + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic(EBadInvariant)); + + //[ 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(EBadInvariant)); + + } + +/** +* MarcReplaceMetaDataEntryL +* @param aIndex +* @param aNewEntry +*/ +void CMMFAudioController::MarcReplaceMetaDataEntryL(TInt aIndex, const CMMFMetaDataEntry& aNewEntry) + { + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic(EBadInvariant)); + + //[ 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(EBadInvariant)); + + } + +/** +* MacSetSourceSampleRateL +* @param aSampleRate +*/ +void CMMFAudioController::MacSetSourceSampleRateL(TUint aSampleRate) + { + // [ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic( EBadInvariant)); + + // [ 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 if (iDataSource && (iDataSource->DataSourceType()==KUidMmfAudioInput)) + { + // cast iDataSource to audio input and set sample rate + MMMFAudioInput* ai = STATIC_CAST(MMMFAudioInput*, iDataSource); + + //note that it is safe to call SoundDevice() + //as the controller logs onto the iDataSource when it is added + TMMFCapabilities devSoundConfig = ai->SoundDevice().Config(); + + ConvertFromSampleRateToDevSoundCapsL(aSampleRate, devSoundConfig); + ai->SoundDevice().SetConfigL(devSoundConfig); + //ReNegotiateL(); + } + else + User::Leave(KErrNotSupported); + + // [assert the post condition ] + __ASSERT_ALWAYS( Invariant(), Panic( EBadInvariant)); + + } + +/** +* MacSetSourceNumChannelsL +* @param aNumChannels +*/ +void CMMFAudioController::MacSetSourceNumChannelsL(TUint aNumChannels) + { + // [ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic( EBadInvariant)); + + // [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 if (iDataSource && (iDataSource->DataSourceType()==KUidMmfAudioInput)) + { + // cast iDataSource to audio input and set num channels + MMMFAudioInput* ai = STATIC_CAST(MMMFAudioInput*, iDataSource); + + //note that it is safe to call SoundDevice() + //as the controller logs onto the iDataSource when it is added + TMMFCapabilities devSoundConfig = ai->SoundDevice().Config(); + + ConvertFromNumChannelsToDevSoundCapsL(aNumChannels, devSoundConfig); + ai->SoundDevice().SetConfigL(devSoundConfig); + //ReNegotiateL(); + } + else + User::Leave(KErrNotSupported); + + // [ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic( EBadInvariant)); + + } + +/** +* MacSetSourceFormatL +* @param aFormatUid +* +*/ +void CMMFAudioController::MacSetSourceFormatL(TUid aFormatUid) + { + //[ assert the invaraint ] + __ASSERT_ALWAYS( Invariant(), Panic( EBadInvariant)); + + // [ 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( EBadInvariant)); + + //[ 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( EBadInvariant)); + + // [ 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 if (iDataSink && (iDataSink->DataSinkType()==KUidMmfAudioOutput)) + { + // cast iDataSink to audio output and set sample rate + MMMFAudioOutput* ao = STATIC_CAST(MMMFAudioOutput*, iDataSink); + + + + TMMFCapabilities devSoundConfig = ao->SoundDevice().Config(); + ConvertFromSampleRateToDevSoundCapsL(aSampleRate, devSoundConfig); + ao->SoundDevice().SetConfigL(devSoundConfig); + } + else + User::Leave(KErrNotSupported); + + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic( EBadInvariant)); + } + +/** +* MacSetSinkNumChannelsL +* @param aNumChannels +* +*/ +void CMMFAudioController::MacSetSinkNumChannelsL(TUint aNumChannels) + { + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic( EBadInvariant)); + + // [ 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 if (iDataSink && (iDataSink->DataSinkType()==KUidMmfAudioOutput)) + { + // cast iDataSink to audio output and set num channels + MMMFAudioOutput* ao = STATIC_CAST(MMMFAudioOutput*, iDataSink); + + //note that it is safe to call SoundDevice() + //as the controller logs onto the iDataSource when it is added + TMMFCapabilities devSoundConfig = ao->SoundDevice().Config(); + ConvertFromNumChannelsToDevSoundCapsL(aNumChannels, devSoundConfig); + ao->SoundDevice().SetConfigL(devSoundConfig); + } + else + User::Leave(KErrNotSupported); + + // [assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic( EBadInvariant)); + + } + +/** +* MacSetSinkFormatL +* @param aFormatUid +* +*/ +void CMMFAudioController::MacSetSinkFormatL(TUid aFormatUid) + { + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic( EBadInvariant)); + + // [ 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( EBadInvariant)); + + //[ 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(EBadInvariant)); + + //[ 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); + } + else if((iDataSink) && (aSinkDataType != KMMFFourCCCodeNULL)) + { + error = iDataSink->SetSinkDataTypeCode(aSinkDataType,iMediaId); + } + if ((iSourceFormat)&&(!error)&&(aSourceDataType != KMMFFourCCCodeNULL)) + { + error = iSourceFormat->SetSourceDataTypeCode(aSourceDataType,iMediaId); + } + else if ((iDataSource) && (aSourceDataType != KMMFFourCCCodeNULL)) + { + error = iDataSource->SetSourceDataTypeCode(aSourceDataType,iMediaId); + } + + //[ leave if we are not ready or there was an error ] + User::LeaveIfError(error); + + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic(EBadInvariant)); + } + +/** +* MacSetSourceBitRateL +* @param "TUint" +* Sets the source bit rate +* +*/ +void CMMFAudioController::MacSetSourceBitRateL(TUint aBitRate) + { + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic(EBadInvariant)); + + //[ 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( EBadInvariant)); + } + + +/** +* +* 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( EBadInvariant)); + + // [ 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( EBadInvariant)); + + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic( EBadInvariant)); + } + +/** +* +* MacSetSinkDataTypeL +* @param "TFourCC" +* +*/ +void CMMFAudioController::MacSetSinkDataTypeL(TFourCC aDataType) + { + //precondition is that we have a sink format + if (!iSinkFormat) + { + User::Leave(KErrNotSupported); + } + + MacSetCodecL(KMMFFourCCCodeNULL, aDataType); + + if (iDataSink && (iDataSink->DataSinkType()==KUidMmfAudioOutput)) + { + MMMFAudioOutput* ao = STATIC_CAST(MMMFAudioOutput*, iDataSink); + TMMFCapabilities devSoundConfig = ao->SoundDevice().Config(); + RArray dataTypes; + CleanupClosePushL(dataTypes); + + //[ set dev sound data type here ] + ConvertFromDataTypeToDevSoundCapsL(aDataType, devSoundConfig); + ao->SoundDevice().SetConfigL(devSoundConfig); + CleanupStack::PopAndDestroy();//dataTypes + } + } + +/** +* +* MacGetSourceSampleRateL +* @param "TUint" +* +*/ +void CMMFAudioController::MacGetSourceSampleRateL(TUint& aRate) + { + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic( EBadInvariant)); + + //[ precondition is that we have a source format || + // we have a data source and its an audio input ] + if( !((iDataSource && (iDataSource->DataSourceType()==KUidMmfAudioInput)) || + ( iSourceFormat ))) + User::Leave(KErrNotSupported); + + if (iSourceFormat) + { + aRate = iSourceFormat->SampleRate(); + } + else + { + // cast iDataSource to audio input and query sample rate + MMMFAudioInput* ai = STATIC_CAST(MMMFAudioInput*, iDataSource); + TMMFCapabilities devSoundConfig = ai->SoundDevice().Config(); + RArray rates; + CleanupClosePushL(rates); + ConvertFromDevSoundCapsToSampleRatesL(devSoundConfig, rates); + ASSERT(rates.Count()==1);//make sure we've been given the correct config by devsound + aRate = rates[0]; + CleanupStack::PopAndDestroy();//rates + } + + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic( EBadInvariant)); + } + +/** +* +* MacGetSourceBitRateL +* @param "TUint" +* +*/ +void CMMFAudioController::MacGetSourceBitRateL(TUint& aRate) + { + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic( EBadInvariant)); + + // 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( EBadInvariant)); + + } + +/** +* +* MacGetSourceNumChannelsL +* @param "TUint&" +* +*/ +void CMMFAudioController::MacGetSourceNumChannelsL(TUint& aNumChannels) + { + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic( EBadInvariant)); + + //[ assert the precondition ] + if( !((iSourceFormat) || + (iDataSource && (iDataSource->DataSourceType()==KUidMmfAudioInput)))) + User::Leave(KErrNotSupported); + + if (iSourceFormat) + { + aNumChannels = iSourceFormat->NumChannels(); + } + else + { + // cast iDataSource to audio input and query num channels + MMMFAudioInput* ai = STATIC_CAST(MMMFAudioInput*, iDataSource); + TMMFCapabilities devSoundConfig = ai->SoundDevice().Config(); + RArray numChannels; + CleanupClosePushL(numChannels); + ConvertFromDevSoundCapsToNumChannelsL(devSoundConfig, numChannels); + ASSERT(numChannels.Count()==1); + aNumChannels = numChannels[0]; + CleanupStack::PopAndDestroy();//numChannels + } + + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic( EBadInvariant)); + + } + +/** +* +* MacGetSourceFormatL +* @param "TUid" +*/ +void CMMFAudioController::MacGetSourceFormatL(TUid& aFormat) + { + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic( EBadInvariant)); + + //[ 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( EBadInvariant)); + + } + +/** +* +* MacGetSourceDataTypeL +* @param "TFourCC&" +* +*/ +void CMMFAudioController::MacGetSourceDataTypeL(TFourCC& aDataType) + { + if (iSourceFormat) + aDataType = iSourceFormat->SourceDataTypeCode(TMediaId(KUidMediaTypeAudio)); + else if (iDataSource && (iDataSource->DataSourceType()==KUidMmfAudioInput)) + { + // cast iDataSource to audio input and query num channels + MMMFAudioInput* ai = STATIC_CAST(MMMFAudioInput*, iDataSource); + TMMFCapabilities devSoundConfig = ai->SoundDevice().Config(); + RArray dataTypes; + CleanupClosePushL(dataTypes); + ConvertFromDevSoundCapsToDataTypesL(devSoundConfig, dataTypes); + ASSERT(dataTypes.Count()==1); + aDataType = dataTypes[0]; + CleanupStack::PopAndDestroy();//dataTypes + } + else + User::Leave(KErrNotSupported); + } + +/** +* +* MacGetSinkSampleRateL +* @param "TUint&" +* +*/ + +void CMMFAudioController::MacGetSinkSampleRateL(TUint& aRate) + { + if (iSinkFormat) + aRate = iSinkFormat->SampleRate(); + else if (iDataSink && (iDataSink->DataSinkType()==KUidMmfAudioOutput)) + { + // cast iDataSink to audio output and query sample rate + MMMFAudioOutput* ao = STATIC_CAST(MMMFAudioOutput*, iDataSink); + TMMFCapabilities devSoundConfig = ao->SoundDevice().Config(); + RArray rates; + CleanupClosePushL(rates); + ConvertFromDevSoundCapsToSampleRatesL(devSoundConfig, rates); + ASSERT(rates.Count()==1);//make sure we've been given the correct config by devsound + aRate = rates[0]; + CleanupStack::PopAndDestroy();//rates + } + else + User::Leave(KErrNotSupported); + } + +/** +* +* 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) + { + if (iSinkFormat) + aNumChannels = iSinkFormat->NumChannels(); + else if (iDataSink && (iDataSink->DataSinkType()==KUidMmfAudioOutput)) + { + // cast iDataSink to audio output and query num channels + MMMFAudioOutput* ao = STATIC_CAST(MMMFAudioOutput*, iDataSink); + TMMFCapabilities devSoundConfig = ao->SoundDevice().Config(); + RArray numChannels; + CleanupClosePushL(numChannels); + ConvertFromDevSoundCapsToNumChannelsL(devSoundConfig, numChannels); + ASSERT(numChannels.Count()==1); + aNumChannels = numChannels[0]; + CleanupStack::PopAndDestroy();//numChannels + } + else + User::Leave(KErrNotSupported); + } + +/** +* +* 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) + { + if (iSinkFormat) + aDataType = iSinkFormat->SinkDataTypeCode(TMediaId(KUidMediaTypeAudio)); + else if (iDataSink && (iDataSink->DataSinkType()==KUidMmfAudioOutput)) + { + // cast iDataSink to audio output and query data type + MMMFAudioOutput* ao = STATIC_CAST(MMMFAudioOutput*, iDataSink); + TMMFCapabilities devSoundConfig = ao->SoundDevice().Config(); + RArray dataTypes; + CleanupClosePushL(dataTypes); + ConvertFromDevSoundCapsToDataTypesL(devSoundConfig, dataTypes); + ASSERT(dataTypes.Count()==1); + aDataType = dataTypes[0]; + CleanupStack::PopAndDestroy();//dataTypes + } + else + User::Leave(KErrNotSupported); + } + +/** +* +* MacGetSupportedSourceSampleRatesL +* @param "RArray&" +* +*/ +void CMMFAudioController::MacGetSupportedSourceSampleRatesL(RArray& aSupportedRates) + { + aSupportedRates.Reset(); + if (iSourceFormat) + iSourceFormat->GetSupportedSampleRatesL(aSupportedRates); + else if (iDataSource && (iDataSource->DataSourceType()==KUidMmfAudioInput)) + { + // cast iDataSource to audio input and query supported sample rates + MMMFAudioInput* ai = STATIC_CAST(MMMFAudioInput*, iDataSource); + TMMFCapabilities devSoundConfig = ai->SoundDevice().Capabilities(); + ConvertFromDevSoundCapsToSampleRatesL(devSoundConfig, aSupportedRates); + } + else + User::Leave(KErrNotSupported); + } + +/** +* +* 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) + { + aSupportedChannels.Reset(); + if (iSourceFormat) + iSourceFormat->GetSupportedNumChannelsL(aSupportedChannels); + else if (iDataSource && (iDataSource->DataSourceType()==KUidMmfAudioInput)) + { + // cast iDataSource to audio input and query supported num channels + MMMFAudioInput* ai = STATIC_CAST(MMMFAudioInput*, iDataSource); + TMMFCapabilities devSoundConfig = ai->SoundDevice().Capabilities(); + ConvertFromDevSoundCapsToNumChannelsL(devSoundConfig, aSupportedChannels); + } + else + User::Leave(KErrNotSupported); + } + +/*** +* +* MacGetSupportedSourceDataTypesL +* @param "RArray&" +* +*/ +void CMMFAudioController::MacGetSupportedSourceDataTypesL(RArray& aSupportedDataTypes) + { + aSupportedDataTypes.Reset(); + if (iSourceFormat) + iSourceFormat->GetSupportedDataTypesL(TMediaId(KUidMediaTypeAudio), aSupportedDataTypes); + else if (iDataSource && (iDataSource->DataSourceType()==KUidMmfAudioInput)) + { + // cast iDataSource to audio input and query supported data types + MMMFAudioInput* ai = STATIC_CAST(MMMFAudioInput*, iDataSource); + TMMFCapabilities devSoundConfig = ai->SoundDevice().Capabilities(); + ConvertFromDevSoundCapsToDataTypesL(devSoundConfig, aSupportedDataTypes); + } + else + User::Leave(KErrNotSupported); + } + +/*** +* +* MacGetSupportedSinkSampleRatesL +* @param "RArray& " +* +*/ +void CMMFAudioController::MacGetSupportedSinkSampleRatesL(RArray& aSupportedRates) + { + aSupportedRates.Reset(); + if (iSinkFormat) + iSinkFormat->GetSupportedSampleRatesL(aSupportedRates); + else if (iDataSink && (iDataSink->DataSinkType()==KUidMmfAudioOutput)) + { + // cast iDataSink to audio output and query supported sample rates + MMMFAudioOutput* ao = STATIC_CAST(MMMFAudioOutput*, iDataSink); + TMMFCapabilities devSoundConfig = ao->SoundDevice().Capabilities(); + ConvertFromDevSoundCapsToSampleRatesL(devSoundConfig, aSupportedRates); + } + else + User::Leave(KErrNotSupported); + } + +/*** +* +* 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) + { + aSupportedChannels.Reset(); + if (iSinkFormat) + iSinkFormat->GetSupportedNumChannelsL(aSupportedChannels); + else if (iDataSink && (iDataSink->DataSinkType()==KUidMmfAudioOutput)) + { + // cast iDataSink to audio output and query supported channels + MMMFAudioOutput* ao = STATIC_CAST(MMMFAudioOutput*, iDataSink); + TMMFCapabilities devSoundConfig = ao->SoundDevice().Capabilities(); + ConvertFromDevSoundCapsToNumChannelsL(devSoundConfig, aSupportedChannels); + } + else + User::Leave(KErrNotSupported); + } + +/*** +* +* MacGetSupportedSinkDataTypesL +* @param "RArray&" +*/ +void CMMFAudioController::MacGetSupportedSinkDataTypesL(RArray& aSupportedDataTypes) + { + aSupportedDataTypes.Reset(); + if (iSinkFormat) + iSinkFormat->GetSupportedDataTypesL(TMediaId(KUidMediaTypeAudio), aSupportedDataTypes); + else if (iDataSink && (iDataSink->DataSinkType()==KUidMmfAudioOutput)) + { + // cast iDataSink to audio output and query supported data types + MMMFAudioOutput* ao = STATIC_CAST(MMMFAudioOutput*, iDataSink); + TMMFCapabilities devSoundConfig = ao->SoundDevice().Capabilities(); + ConvertFromDevSoundCapsToDataTypesL(devSoundConfig, aSupportedDataTypes); + } + else + User::Leave(KErrNotSupported); + } + +/** +* +* 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( EBadInvariant )); + + // [ 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( EBadInvariant )); + + 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( EBadInvariant ) ); + //[ 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( EBadInvariant ) ); + 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) + { + return KErrNotReady; + } + + 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) + { + return KErrNotReady; + } + + 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) + { + return KErrNotReady; + } + + 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(EBadInvariant)); + //[ 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(EBadInvariant)); + } + +void CMMFAudioController::MarnCancelRegisterAsClientL(TUid aEventType) + { + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic(EBadInvariant)); + //[ 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(EBadInvariant)); + } + +void CMMFAudioController::MarnGetResourceNotificationDataL(TUid aEventType,TDes8& aNotificationData) + { + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic(EBadInvariant)); + //[ 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 contains an offset = the number of samples played. + // 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(EBadInvariant)); + } + +void CMMFAudioController::MarnWillResumePlayL() + { + //[ assert the invariant ] + __ASSERT_ALWAYS( Invariant(), Panic(EBadInvariant)); + //[ 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(EBadInvariant)); + } + +// ----------------------------------------------------------------------------- +// From MCustomInterfaceCustomCommandImplementor +// Provides the default implementation. +// ----------------------------------------------------------------------------- +// +const TMMFMessageDestination& CMMFAudioController::GetCustomInterfaceBuilderL() + { + // If an effects manager already exist just return the handle to it + // otherwise, create one. + if ( !iCustomInterfaceBuilder ) + { + CMMFDevSound* mmfDevSound = NULL; + + if (iDataSource && iSinkFormat) //record + { + MMMFAudioInput* audioInput = STATIC_CAST(MMMFAudioInput*, iDataSource); + mmfDevSound = &audioInput->SoundDevice(); + } + else if (iDataSink && iSourceFormat) //play + { + MMMFAudioOutput* audioOutput = STATIC_CAST(MMMFAudioOutput*, iDataSink); + mmfDevSound = &audioOutput->SoundDevice(); + } + + if (mmfDevSound) + { + iCustomInterfaceBuilder = CCustomInterfaceBuilder::NewL(MMFObjectContainerL(), + *mmfDevSound); + TBool secure = EFalse; + secure = CMMFController::IsSecureDrmModeL(); + iCustomInterfaceBuilder->SetSecureCustomInterfaces( secure ); + + // Append custom interface builder to the array of MMFObjects + User::LeaveIfError(MMFObjectContainerL().AddMMFObject(*iCustomInterfaceBuilder)); + } + else + { + User::Leave(KErrNotReady); + } + } + + return iCustomInterfaceBuilder->Handle(); + }