// Copyright (c) 2002-2009 Nokia Corporation and/or its subsidiary(-ies).
// All rights reserved.
// This component and the accompanying materials are made available
// under the terms of "Eclipse Public License v1.0"
// which accompanies this distribution, and is available
// at the URL "http://www.eclipse.org/legal/epl-v10.html".
//
// Initial Contributors:
// Nokia Corporation - initial contribution.
//
// Contributors:
//
// Description:
//
#include <mmf/common/mmfpaniccodes.h>
#include "mmfclienttoneplayer.h"
using namespace ContentAccess;
enum TMmfMdaAudioToneUtility
{
EBadArgument,
EPostConditionViolation,
EPlayStartedCalledWithError
};
// declared in the recorder module
void Panic(TInt aPanicCode);
/**
Creates a new instance of the tone player utility.
The default volume is set to MaxVolume() / 2.
@param aObserver
A class to receive notifications from the tone player.
@param aServer
This parameter is no longer used and should be NULL.
@return A pointer to the new audio tone player utility object.
@since 5.0
*/
EXPORT_C CMdaAudioToneUtility* CMdaAudioToneUtility::NewL(MMdaAudioToneObserver& aObserver, CMdaServer* aServer /*= NULL*/)
{
return CMdaAudioToneUtility::NewL(aObserver, aServer, EMdaPriorityNormal, EMdaPriorityPreferenceTimeAndQuality);
}
/**
Creates a new instance of the tone player utility.
The default volume is set to MaxVolume() / 2.
@param aObserver
A class to receive notifications from the tone player
@param aServer
This parameter is no longer used and should be NULL
@param aPriority
The Priority Value - this client's relative priority. This is a value between EMdaPriorityMin and
EMdaPriorityMax and represents a relative priority. A higher value indicates a more important request.
@param aPref
The Priority Preference - an additional audio policy parameter. The suggested default is
EMdaPriorityPreferenceNone. Further values are given by TMdaPriorityPreference, and additional
values may be supported by given phones and/or platforms, but should not be depended upon by
portable code.
@return A pointer to the new audio tone player utility object.
@since 5.0
Note: The Priority Value and Priority Preference are used primarily when deciding what to do when
several audio clients attempt to play or record simultaneously. In addition to the Priority Value and Preference,
the adaptation may consider other parameters such as the SecureId and Capabilities of the client process.
Whatever, the decision as to what to do in such situations is up to the audio adaptation, and may
vary between different phones. Portable applications are advised not to assume any specific behaviour.
*/
EXPORT_C CMdaAudioToneUtility* CMdaAudioToneUtility::NewL(MMdaAudioToneObserver& aObserver, CMdaServer* /*aServer = NULL*/,
TInt aPriority /*= EMdaPriorityNormal*/,
TInt aPref /*= EMdaPriorityPreferenceTimeAndQuality*/)
{
CMdaAudioToneUtility* self = new(ELeave) CMdaAudioToneUtility();
CleanupStack::PushL(self);
self->iProperties = CMMFMdaAudioToneUtility::NewL(aObserver, NULL, aPriority, aPref);
CleanupStack::Pop(); //self
return self;
}
/**
Destructor. Frees any resources held by the tone player
@since 5.0
*/
CMdaAudioToneUtility::~CMdaAudioToneUtility()
{
delete iProperties;
}
/**
Returns the current state of the audio tone utility.
@return The state of the audio tone utility.
@since 5.0
*/
TMdaAudioToneUtilityState CMdaAudioToneUtility::State()
{
ASSERT(iProperties);
return iProperties->State();
}
/**
Returns the maximum volume supported by the device. This is the maximum value which can be
passed to CMdaAudioToneUtility::SetVolume().
@return The maximum volume. This value is platform dependent but is always greater than or equal to one.
@since 5.0
*/
TInt CMdaAudioToneUtility::MaxVolume()
{
ASSERT(iProperties);
return iProperties->MaxVolume();
}
/**
Returns an integer representing the current volume of the audio device.
@return The current volume.
@since 5.0
*/
TInt CMdaAudioToneUtility::Volume()
{
ASSERT(iProperties);
return iProperties->Volume();
}
/**
Changes the volume of the audio device.
The volume can be changed before or during play and is effective
immediately.
@param aVolume
The volume setting. This can be any value from zero to
the value returned by a call to
CMdaAudioToneUtility::MaxVolume().
Setting a zero value mutes the sound. Setting the
maximum value results in the loudest possible sound.
@since 5.0
*/
void CMdaAudioToneUtility::SetVolume(TInt aVolume)
{
ASSERT(iProperties);
iProperties->SetVolume(aVolume);
}
/**
Changes the clients priority.
@param aPriority
The Priority Value.
@param aPref
The Priority Preference.
@see CMdaAudioToneUtility::NewL()
@since 5.0
*/
void CMdaAudioToneUtility::SetPriority(TInt aPriority, TInt aPref)
{
ASSERT(iProperties);
iProperties->SetPriority(aPriority, aPref);
}
/**
Changes the duration of DTMF tones, the gaps between DTMF tones and the
pauses.
@param aToneLength
The duration of the DTMF tone in microseconds.
@param aToneOffLength
The gap between DTFM tones in microseconds.
@param aPauseLength
Pauses in microseconds
*/
void CMdaAudioToneUtility::SetDTMFLengths(TTimeIntervalMicroSeconds32 aToneLength,
TTimeIntervalMicroSeconds32 aToneOffLength,
TTimeIntervalMicroSeconds32 aPauseLength)
{
ASSERT(iProperties);
iProperties->SetDTMFLengths(aToneLength, aToneOffLength, aPauseLength);
}
/**
Sets the number of times the tone sequence is to be repeated during
the play operation.
A period of silence can follow each playing of the tone sequence. The
tone sequence can be repeated indefinitely.
@param aRepeatNumberOfTimes
The number of times the tone sequence, together with
the trailing silence, is to be repeated. If this is
set to KMdaRepeatForever, then the tone
sequence, together with the trailing silence, is
repeated indefinitely. The behaviour is undefined for values other than
KMdaRepeatForever, zero and positive.
@param aTrailingSilence
The time interval of the training silence. The behaviour is undefined
for values other than zero and positive.
@since 5.0
*/
void CMdaAudioToneUtility::SetRepeats(TInt aRepeatNumberOfTimes,
const TTimeIntervalMicroSeconds& aTrailingSilence)
{
ASSERT(iProperties);
iProperties->SetRepeats(aRepeatNumberOfTimes, aTrailingSilence);
}
/**
Defines the period over which the volume level is to rise smoothly
from nothing to the normal volume level.
@param aRampDuration
The period over which the volume is to rise. A zero
value causes the tone to be played at the normal level
for the full duration of the playback. A value which
is longer than the duration of the tone sequence means
that the tone never reaches its normal volume level.
@since 5.0
*/
void CMdaAudioToneUtility::SetVolumeRamp(const TTimeIntervalMicroSeconds& aRampDuration)
{
ASSERT(iProperties);
iProperties->SetVolumeRamp(aRampDuration);
}
/**
Returns the number of available pre-defined tone sequences.
@return The number of tone sequences. This value is implementation
dependent but is always greater than or equal to zero.
@since 5.0
*/
TInt CMdaAudioToneUtility::FixedSequenceCount()
{
ASSERT(iProperties);
return iProperties->FixedSequenceCount();
}
/**
Returns the name assigned to a specific pre-defined tone sequence.
@param aSequenceNumber
The index identifying the specific pre-defined tone sequence.
Index values are relative to zero. This can be any value from
zero to the value returned by a call to FixedSequenceCount() - 1.
The function raises a panic if sequence number is not within this
range.
@see CMMFDevSound::FixedSequenceName(TInt aSequenceNumber)
@see FixedSequenceCount()
@return The name assigned to the tone sequence.
@since 5.0
*/
const TDesC& CMdaAudioToneUtility::FixedSequenceName(TInt aSequenceNumber)
{
ASSERT(iProperties);
return iProperties->FixedSequenceName(aSequenceNumber);
}
/**
Configures the audio tone player utility to play a single tone.
This function is asynchronous. On completion, the observer callback
function MMdaAudioToneObserver::MatoPrepareComplete() is
called, indicating the success or failure of the configuration
operation.The configuration operation can be cancelled by calling
CMdaAudioToneUtility::CancelPrepare(). The configuration
operation cannot be started if a play operation is in progress.
@param aFrequency
The frequency (pitch) of the tone in Hz.
@param aDuration
The duration of the tone in microseconds.
@since 5.0
*/
void CMdaAudioToneUtility::PrepareToPlayTone(TInt aFrequency, const TTimeIntervalMicroSeconds& aDuration)
{
ASSERT(iProperties);
iProperties->PrepareToPlayTone(aFrequency, aDuration);
}
/**
Configures the audio tone player utility to play a dual tone.
The generated tone consists of two sine waves of different
frequencies summed together.
This function is asynchronous. On completion, the observer callback
function MMdaAudioToneObserver::MatoPrepareComplete() is
called, indicating the success or failure of the configuration
operation. The configuration operation can be cancelled by calling
CMdaAudioToneUtility::CancelPrepare(). The configuration
operation cannot be started if a play operation is in progress.
@param aFrequencyOne
The first frequency (pitch) of the tone.
@param aFrequencyTwo
The second frequency (pitch) of the tone.
@param aDuration
The duration of the tone in microseconds.
@since 7.0sy
*/
EXPORT_C void CMdaAudioToneUtility::PrepareToPlayDualTone(TInt aFrequencyOne, TInt aFrequencyTwo, const TTimeIntervalMicroSeconds& aDuration)
{
ASSERT(iProperties);
iProperties->PrepareToPlayDualTone(aFrequencyOne, aFrequencyTwo, aDuration);
}
/**
Configures the audio tone utility player to play a DTMF (Dual-Tone
Multi-Frequency) string.
This function is asynchronous. On completion, the observer callback
function MMdaAudioToneObserver::MatoPrepareComplete() is
called, indicating the success or failure of the configuration
operation. The configuration operation can be cancelled by calling
CMdaAudioToneUtility::CancelPrepare(). The configuration
operation cannot be started if a play operation is in progress.
@param aDTMF
A descriptor containing the DTMF string.
@since 5.0
*/
void CMdaAudioToneUtility::PrepareToPlayDTMFString(const TDesC& aDTMF)
{
ASSERT(iProperties);
iProperties->PrepareToPlayDTMFString(aDTMF);
}
/**
Configures the audio tone player utility to play a tone sequence
contained in a descriptor.
This function is asynchronous. On completion, the observer callback
function MMdaAudioToneObserver::MatoPrepareComplete() is
called, indicating the success or failure of the configuration
operation. The configuration operation can be cancelled by calling
CMdaAudioToneUtility::CancelPrepare(). The configuration
operation cannot be started if a play operation is in progress.
@param aSequence
The descriptor containing the tone sequence. The
format of the data is unspecified but is expected to
be platform dependent. A device might support more
than one form of sequence data.
@since 5.0
*/
void CMdaAudioToneUtility::PrepareToPlayDesSequence(const TDesC8& aSequence)
{
ASSERT(iProperties);
iProperties->PrepareToPlayDesSequence(aSequence);
}
/**
Configures the audio tone player utility to play a tone sequence
contained in a file.
This function is asynchronous. On completion, the observer callback
function MMdaAudioToneObserver::MatoPrepareComplete() is
called, indicating the success or failure of the configuration
operation. The configuration operation can be cancelled by calling
CMdaAudioToneUtility::CancelPrepare(). The configuration
operation cannot be started if a play operation is in progress.
@param aFileName
The full path name of the file containing the tone
sequence. The format of the data is unspecified but is
expected to be platform dependent. A device might
support more than one form of sequence data.
@since 5.0
*/
void CMdaAudioToneUtility::PrepareToPlayFileSequence(const TDesC& aFileName)
{
ASSERT(iProperties);
iProperties->PrepareToPlayFileSequence(aFileName);
}
/**
Configures the audio tone player utility to play a tone sequence
contained in a file.
This function is asynchronous. On completion, the observer callback
function MMdaAudioToneObserver::MatoPrepareComplete() is
called, indicating the success or failure of the configuration
operation. The configuration operation can be cancelled by calling
CMdaAudioToneUtility::CancelPrepare(). The configuration
operation cannot be started if a play operation is in progress.
@param aFile
A handle to an open file containing the tone
sequence. The format of the data is unspecified but is
expected to be platform dependent. A device might
support more than one form of sequence data.
@since 5.0
*/
EXPORT_C void CMdaAudioToneUtility::PrepareToPlayFileSequence(RFile& aFile)
{
ASSERT(iProperties);
iProperties->PrepareToPlayFileSequence(aFile);
}
/**
Configures the audio tone player utility to play the specified
pre-defined tone sequence.
This function is asynchronous. On completion, the observer callback
function MMdaAudioToneObserver::MatoPrepareComplete() is
called, indicating the success or failure of the configuration
operation. The configuration operation can be cancelled by calling
CMdaAudioToneUtility::CancelPrepare(). The configuration
operation cannot be started if a play operation is in progress.
@param aSequenceNumber
An index into the set of pre-defined tone sequences.
This can be any value from zero to the value returned by a
call to FixedSequenceCount() - 1.
If the sequence number is not within this range, a panic will be
raised when Play() is called later.
@see FixedSequenceCount()
@see CMMFDevSound::PlayFixedSequenceL(TInt aSequenceNumber)
@since 5.0
*/
void CMdaAudioToneUtility::PrepareToPlayFixedSequence(TInt aSequenceNumber)
{
ASSERT(iProperties);
iProperties->PrepareToPlayFixedSequence(aSequenceNumber);
}
/**
Cancels the configuration operation.
The observer callback function
MMdaAudioToneObserver::MatoPrepareComplete() is not
called.
@since 5.0
*/
void CMdaAudioToneUtility::CancelPrepare()
{
ASSERT(iProperties);
iProperties->CancelPrepare();
}
/**
Plays the tone.
The tone played depends on the current configuration.This function is
asynchronous. On completion, the observer callback function
MMdaAudioToneObserver::MatoPlayComplete() is called,
indicating the success or failure of the play operation.The play
operation can be cancelled by
calling CMdaAudioToneUtility::CancelPlay().
@since 5.0
*/
void CMdaAudioToneUtility::Play()
{
ASSERT(iProperties);
iProperties->Play();
}
EXPORT_C TInt CMdaAudioToneUtility::Pause()
{
ASSERT(iProperties);
return iProperties->Pause();
}
EXPORT_C TInt CMdaAudioToneUtility::Resume()
{
ASSERT(iProperties);
return iProperties->Resume();
}
/**
Cancels the tone playing operation.
The observer callback
function MMdaAudioToneObserver::MatoPlayComplete() is not
called.
@since 5.0
*/
void CMdaAudioToneUtility::CancelPlay()
{
ASSERT(iProperties);
iProperties->CancelPlay();
}
/**
Sets the stereo balance for playback.
@param aBalance
The balance. Should be between KMMFBalanceMaxLeft and KMMFBalanceMaxRight.
@return An error code indicating if the function call was successful. KErrNone on success, otherwise
another of the system-wide error codes.
@since 7.0s
*/
EXPORT_C void CMdaAudioToneUtility::SetBalanceL(TInt aBalance /*=KMMFBalanceCenter*/)
{
ASSERT(iProperties);
iProperties->SetBalanceL(aBalance);
}
/**
* Returns The current playback balance.This function may not return the same value
* as passed to SetBalanceL depending on the internal implementation in
* the underlying components.
*
* @return The balance. Should be between KMMFBalanceMaxLeft and KMMFBalanceMaxRight.
*
* @since 7.0s
*/
EXPORT_C TInt CMdaAudioToneUtility::GetBalanceL()
{
ASSERT(iProperties);
return iProperties->GetBalanceL();
}
/**
Retrieves a custom interface to the underlying device.
@param aInterfaceId
The interface UID, defined with the custom interface.
@return A pointer to the interface implementation, or NULL if the device does not
implement the interface requested. The return value must be cast to the
correct type by the user.
*/
EXPORT_C TAny* CMdaAudioToneUtility::CustomInterface(TUid aInterfaceId)
{
ASSERT(iProperties);
return iProperties->CustomInterface(aInterfaceId);
}
EXPORT_C void CMdaAudioToneUtility::RegisterPlayStartCallback(MMdaAudioTonePlayStartObserver& aObserver)
{
ASSERT(iProperties);
iProperties->RegisterPlayStartCallback(aObserver);
}
CMMFMdaAudioToneUtility* CMMFMdaAudioToneUtility::NewL(MMdaAudioToneObserver& aObserver, CMdaServer* /*aServer = NULL*/,
TInt aPriority /*= EMdaPriorityNormal*/,
TInt aPref /*= EMdaPriorityPreferenceTimeAndQuality*/)
{
CMMFMdaAudioToneUtility* self = new(ELeave) CMMFMdaAudioToneUtility(aObserver, aPriority, aPref);
CleanupStack::PushL(self);
self->ConstructL();
CleanupStack::Pop(self);
return self;
}
CMMFMdaAudioToneUtility::CMMFMdaAudioToneUtility(MMdaAudioToneObserver& aCallback, TInt aPriority, TInt aPref) :
iCallback(aCallback)
{
iPrioritySettings.iPref = aPref;
iPrioritySettings.iPriority = aPriority;
iState = EMdaAudioToneUtilityNotReady;
iInitialized = EFalse;
iPlayCalled = EFalse;
#ifdef _DEBUG
iPlayCalledBeforeInitialized = EFalse;
#endif
}
void CMMFMdaAudioToneUtility::ConstructL()
{
iAsyncCallback = CMMFMdaAudioToneObserverCallback::NewL(*this, *this);
iDevSound = CMMFDevSound::NewL();
iDevSound->InitializeL(*this,EMMFStateTonePlaying);
// In some implementations InitializeComplete() returns in the InitializeL() context,
// check the error
User::LeaveIfError(iInitializeState);
iDevSound->SetPrioritySettings(iPrioritySettings);
SetVolume(MaxVolume()/2 ); // set the volume to an intermediate value
}
CMMFMdaAudioToneUtility::~CMMFMdaAudioToneUtility()
{
delete iDevSound;
delete iAsyncCallback;
delete iToneConfig;
}
void CMMFMdaAudioToneUtility::InitializeComplete(TInt aError)
{
#ifdef _DEBUG
__ASSERT_ALWAYS(!iPlayCalledBeforeInitialized, User::Panic(_L("PlayInitialized called before InitializeComplete"), 0));
#endif
iInitialized = ETrue;
if (iPlayCalled)
{
// Play() is called before InitializeComplete()
if (aError == KErrNone)
{
PlayAfterInitialized();
}
else
{
// InitializeComplete() with error other than KErrNone
iState = EMdaAudioToneUtilityNotReady;
iAsyncCallback->MatoPlayComplete(aError);
}
iPlayCalled = EFalse;
}
iInitializeState = aError;
}
void CMMFMdaAudioToneUtility::ToneFinished(TInt aError)
{
if (aError != KErrCancel)
{
if (aError == KErrUnderflow)
{
aError = KErrNone;
}
iAsyncCallback->MatoPlayComplete(aError);
}
// else don't want to callback after a cancel
}
TMdaAudioToneUtilityState CMMFMdaAudioToneUtility::State()
{
return iState;
}
TInt CMMFMdaAudioToneUtility::MaxVolume()
{
return iDevSound->MaxVolume();
}
TInt CMMFMdaAudioToneUtility::Volume()
{
return iDevSound->Volume();
}
void CMMFMdaAudioToneUtility::SetVolume(TInt aVolume)
{
iDevSound->SetVolume(aVolume);
}
void CMMFMdaAudioToneUtility::SetPriority(TInt aPriority, TInt aPref)
{
iPrioritySettings.iPref = aPref;
iPrioritySettings.iPriority = aPriority;
iDevSound->SetPrioritySettings(iPrioritySettings);
}
void CMMFMdaAudioToneUtility::SetDTMFLengths(TTimeIntervalMicroSeconds32 aToneLength,
TTimeIntervalMicroSeconds32 aToneOffLength,
TTimeIntervalMicroSeconds32 aPauseLength)
{
iDevSound->SetDTMFLengths(aToneLength, aToneOffLength, aPauseLength);
}
void CMMFMdaAudioToneUtility::SetRepeats(TInt aRepeatNumberOfTimes, const TTimeIntervalMicroSeconds& aTrailingSilence)
{
iDevSound->SetToneRepeats(aRepeatNumberOfTimes, aTrailingSilence);
}
void CMMFMdaAudioToneUtility::SetVolumeRamp(const TTimeIntervalMicroSeconds& aRampDuration)
{
iDevSound->SetVolumeRamp(aRampDuration);
}
TInt CMMFMdaAudioToneUtility::FixedSequenceCount()
{
return iDevSound->FixedSequenceCount();
}
const TDesC& CMMFMdaAudioToneUtility::FixedSequenceName(TInt aSequenceNumber)
{
return iDevSound->FixedSequenceName(aSequenceNumber);
}
/**
* 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 CMMFMdaAudioToneUtility::CalculateBalance( TInt& aBalance, TInt aLeft, TInt aRight ) const
{
//[ assert pre conditions ]
__ASSERT_ALWAYS( (( aLeft + aRight ) == 100 ), Panic( EBadArgument ));
__ASSERT_ALWAYS( (( 0 <= aLeft) && ( 100 >= aLeft)), Panic( EBadArgument) );
__ASSERT_ALWAYS( (( 0 <= aRight) && ( 100 >= aRight)), Panic( EBadArgument) );
aBalance = (aLeft * (KMMFBalanceMaxLeft-KMMFBalanceMaxRight))/100 + KMMFBalanceMaxRight;
//[ assert post condition that aBalance is within limits ]
__ASSERT_ALWAYS( !(aBalance < KMMFBalanceMaxLeft || aBalance > KMMFBalanceMaxRight), Panic(EBadArgument));
}
/**
* CalculateLeftRightBalance
* @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 CMMFMdaAudioToneUtility::CalculateLeftRightBalance( TInt& aLeft, TInt& aRight, TInt aBalance ) const
{
// [ 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));
}
void CMMFMdaAudioToneUtility::SetBalanceL(TInt aBalance)
{
TInt left;
TInt right;
CalculateLeftRightBalance(left,right,aBalance);
iDevSound->SetPlayBalanceL(left,right);
}
TInt CMMFMdaAudioToneUtility::GetBalanceL()
{
TInt left;
TInt right;
TInt balance;
iDevSound->GetPlayBalanceL(left, right);
CalculateBalance(balance,left,right);
return balance;
}
void CMMFMdaAudioToneUtility::PrepareToPlayTone(TInt aFrequency, const TTimeIntervalMicroSeconds& aDuration)
{
delete iToneConfig;
iToneConfig = NULL;
TRAPD(error, iToneConfig = CMMFSimpleToneConfig::NewL(aFrequency, aDuration));
iAsyncCallback->MatoPrepareComplete(error);
}
void CMMFMdaAudioToneUtility::PrepareToPlayDualTone(TInt aFrequencyOne, TInt aFrequencyTwo, const TTimeIntervalMicroSeconds& aDuration)
{
delete iToneConfig;
iToneConfig = NULL;
TRAPD(error, iToneConfig = CMMFDualToneConfig::NewL(aFrequencyOne, aFrequencyTwo, aDuration));
iAsyncCallback->MatoPrepareComplete(error);
}
void CMMFMdaAudioToneUtility::PrepareToPlayDTMFString(const TDesC& aDTMF)
{
delete iToneConfig;
iToneConfig = NULL;
TRAPD(error, iToneConfig = CMMFDTMFStringToneConfig::NewL(aDTMF));
iAsyncCallback->MatoPrepareComplete(error);
}
void CMMFMdaAudioToneUtility::PrepareToPlayDesSequence(const TDesC8& aSequence)
{
delete iToneConfig;
iToneConfig = NULL;
TRAPD(error, iToneConfig = CMMFDesSeqToneConfig::NewL(aSequence));
iAsyncCallback->MatoPrepareComplete(error);
}
void CMMFMdaAudioToneUtility::PrepareToPlayFileSequence(const TDesC& aFileName)
{
delete iToneConfig;
iToneConfig = NULL;
TRAPD(error, iToneConfig = CMMFFileSeqToneConfig::NewL(aFileName));
iAsyncCallback->MatoPrepareComplete(error);
}
void CMMFMdaAudioToneUtility::PrepareToPlayFileSequence(RFile& aFileName)
{
delete iToneConfig;
iToneConfig = NULL;
TRAPD(error, iToneConfig = CMMFFileSeqToneConfig::NewL(aFileName));
iAsyncCallback->MatoPrepareComplete(error);
}
void CMMFMdaAudioToneUtility::PrepareToPlayFixedSequence(TInt aSequenceNumber)
{
delete iToneConfig;
iToneConfig = NULL;
TRAPD(error, iToneConfig = CMMFFixedSeqToneConfig::NewL(aSequenceNumber));
iSequenceNumber = aSequenceNumber;
iAsyncCallback->MatoPrepareComplete(error);
}
void CMMFMdaAudioToneUtility::CancelPrepare()
{
// FIXME - do we need to cancel the callback? What if the callback is actually calling back another error? Probably best not to cancel...
delete iToneConfig;
iToneConfig = NULL;
if (iState == EMdaAudioToneUtilityPrepared)
{
iState = EMdaAudioToneUtilityNotReady;
}
// Cancel the AO
iAsyncCallback->Cancel();
}
TInt CMMFMdaAudioToneUtility::Pause()
{
// Handle scenario when Pause is called before playback has started
if (iState != EMdaAudioToneUtilityPlaying || (iState == EMdaAudioToneUtilityPlaying && !iInitialized))
{
return KErrNotReady;
}
else if(! iDevSound->IsResumeSupported() || iToneConfig->Type() != CMMFToneConfig::EMmfToneTypeFileSeq)
{
return KErrNotSupported;
}
iDevSound->Pause();
iState = EMdaAudioToneUtilityPaused;
return KErrNone;
}
TInt CMMFMdaAudioToneUtility::Resume()
{
TInt err = KErrNone;
if (iState != EMdaAudioToneUtilityPaused)
{
err = KErrNotReady;
}
else if( iDevSound->IsResumeSupported() == EFalse || iToneConfig->Type() != CMMFToneConfig::EMmfToneTypeFileSeq)
{
err = KErrNotSupported;
}
if(err == KErrNone)
{
err = iDevSound->Resume();
if(err == KErrNone)
{
iState = EMdaAudioToneUtilityPlaying;
}
}
return err;
}
void CMMFMdaAudioToneUtility::Play()
{
TInt error = KErrNone;
if ((iState == EMdaAudioToneUtilityPlaying) || (iState == EMdaAudioToneUtilityPaused) || iPlayCalled)
{
error = KErrInUse;
}
if (!error)
{
if (!iToneConfig)
{
TRAP(error, iToneConfig = CMMFFixedSeqToneConfig::NewL(iSequenceNumber));
}
}
// If there was an error, notify the client now. Otherwise, client will be notified when
// play has finished.
if (error)
{
iState = EMdaAudioToneUtilityNotReady;
iAsyncCallback->MatoPlayComplete(error);
}
if (!error)
{
iState = EMdaAudioToneUtilityPlaying;
if (iInitialized)
{
// Play() is called after InitializeComplete()
if (iInitializeState)
{
// InitializeComplete() with error other than KErrNone
iState = EMdaAudioToneUtilityNotReady;
iAsyncCallback->MatoPlayComplete(iInitializeState);
}
else
{
PlayAfterInitialized();
}
}
else
{
// Play() is called before InitializeComplete()
iPlayCalled = ETrue;
}
}
}
void CMMFMdaAudioToneUtility::PlayAfterInitialized()
{
#ifdef _DEBUG
if (iInitialized == EFalse)
{
iPlayCalledBeforeInitialized = ETrue;
}
#endif
TInt error = KErrNone;
switch (iToneConfig->Type())
{
case CMMFToneConfig::EMmfToneTypeSimple:
{
CMMFSimpleToneConfig* c = STATIC_CAST(CMMFSimpleToneConfig*, iToneConfig);
TRAP(error, iDevSound->PlayToneL(c->Frequency(), c->Duration()));
break;
}
case CMMFToneConfig::EMmfToneTypeDual:
{
CMMFDualToneConfig* c = STATIC_CAST(CMMFDualToneConfig*, iToneConfig);
TRAP(error, iDevSound->PlayDualToneL(c->FrequencyOne(), c->FrequencyTwo(), c->Duration()));
break;
}
case CMMFToneConfig::EMmfToneTypeDTMF:
{
CMMFDTMFStringToneConfig* c = STATIC_CAST(CMMFDTMFStringToneConfig*, iToneConfig);
TRAP(error, iDevSound->PlayDTMFStringL(c->DTMF()));
break;
}
case CMMFToneConfig::EMmfToneTypeDesSeq:
{
CMMFDesSeqToneConfig* c = STATIC_CAST(CMMFDesSeqToneConfig*, iToneConfig);
TRAP(error, iDevSound->PlayToneSequenceL(c->DesSeq()));
break;
}
case CMMFToneConfig::EMmfToneTypeFileSeq:
{
CMMFFileSeqToneConfig* c = STATIC_CAST(CMMFFileSeqToneConfig*, iToneConfig);
// check we have rights to play
TRAP(error, c->ExecuteIntentL());
// if we have rights then go ahead and play
if (error == KErrNone)
{
TRAP(error, iDevSound->PlayToneSequenceL(c->FileSeq()));
}
break;
}
case CMMFToneConfig::EMmfToneTypeFixedSeq:
{
CMMFFixedSeqToneConfig* c = STATIC_CAST(CMMFFixedSeqToneConfig*, iToneConfig);
TRAP(error, iDevSound->PlayFixedSequenceL(c->SequenceNumber()));
break;
}
default:
{
User::Panic(KMMFMdaAudioToneUtilityPanicCategory, EMMFMdaAudioToneUtilityBadToneConfig);
break;
}
}
// If there was an error, notify the client now. Otherwise, client will be notified when
// play has finished.
if (error)
{
iState = EMdaAudioToneUtilityNotReady;
iAsyncCallback->MatoPlayComplete(error);
}
else
{
iAsyncCallback->MatoPlayStarted(KErrNone);
}
}
void CMMFMdaAudioToneUtility::CancelPlay()
{
iDevSound->Stop();
if(iState == EMdaAudioToneUtilityPlaying || iState == EMdaAudioToneUtilityPaused)
{
iState = EMdaAudioToneUtilityPrepared;
}
// Cancel the AO
iAsyncCallback->Cancel();
iPlayCalled = EFalse;
}
void CMMFMdaAudioToneUtility::SendEventToClient(const TMMFEvent& /*aEvent*/)
{
if(iState == EMdaAudioToneUtilityPlaying)
{
iState = EMdaAudioToneUtilityPrepared;
}
iAsyncCallback->MatoPlayComplete(KErrInUse);
}
void CMMFMdaAudioToneUtility::RegisterPlayStartCallback(MMdaAudioTonePlayStartObserver& aObserver)
{
iPlayStartObserver = &aObserver;
}
void CMMFMdaAudioToneUtility::MatoPrepareComplete(TInt aError)
{
if (!aError)
{
iState = EMdaAudioToneUtilityPrepared;
}
else
{
iState = EMdaAudioToneUtilityNotReady;
}
iCallback.MatoPrepareComplete(aError);
}
void CMMFMdaAudioToneUtility::MatoPlayComplete(TInt aError)
{
iState = EMdaAudioToneUtilityPrepared;
iCallback.MatoPlayComplete(aError);
}
void CMMFMdaAudioToneUtility::MatoPlayStarted(TInt aError)
{
__ASSERT_DEBUG(aError==KErrNone, Panic(EPlayStartedCalledWithError));
// Not always there is an observer registered
if(iPlayStartObserver)
{
iPlayStartObserver->MatoPlayStarted(aError);
}
}
// CustomInferface - just pass on to DevSound.
TAny* CMMFMdaAudioToneUtility::CustomInterface(TUid aInterfaceId)
{
return iDevSound->CustomInterface(aInterfaceId);
}
CMMFMdaAudioToneObserverCallback* CMMFMdaAudioToneObserverCallback::NewL(MMdaAudioToneObserver& aCallback, MMdaAudioTonePlayStartObserver& aPlayStartCallback)
{
return new(ELeave) CMMFMdaAudioToneObserverCallback(aCallback, aPlayStartCallback);
}
CMMFMdaAudioToneObserverCallback::CMMFMdaAudioToneObserverCallback(MMdaAudioToneObserver& aCallback, MMdaAudioTonePlayStartObserver& aPlayStartCallback) :
CActive(CActive::EPriorityHigh),
iCallback(aCallback),
iPlayStartCallback(aPlayStartCallback)
{
CActiveScheduler::Add(this);
}
CMMFMdaAudioToneObserverCallback::~CMMFMdaAudioToneObserverCallback()
{
Cancel();
}
void CMMFMdaAudioToneObserverCallback::MatoPrepareComplete(TInt aError)
{
iAction = EPrepareComplete;
iErrorCode = aError;
TRequestStatus* s = &iStatus;
SetActive();
User::RequestComplete(s, KErrNone);
}
void CMMFMdaAudioToneObserverCallback::MatoPlayComplete(TInt aError)
{
iAction = EPlayComplete;
iErrorCode = aError;
TRequestStatus* s = &iStatus;
SetActive();
User::RequestComplete(s, KErrNone);
}
void CMMFMdaAudioToneObserverCallback::MatoPlayStarted(TInt aError)
{
iAction = EPlayStarted;
iErrorCode = aError;
TRequestStatus* s = &iStatus;
SetActive();
User::RequestComplete(s, KErrNone);
}
void CMMFMdaAudioToneObserverCallback::RunL()
{
switch (iAction)
{
case EPrepareComplete:
{
iCallback.MatoPrepareComplete(iErrorCode);
break;
}
case EPlayComplete:
{
iCallback.MatoPlayComplete(iErrorCode);
break;
}
case EPlayStarted:
iPlayStartCallback.MatoPlayStarted(iErrorCode);
break;
}
}
void CMMFMdaAudioToneObserverCallback::DoCancel()
{
//nothing to cancel
}
// Tone config classes
// Simple Tone
CMMFToneConfig* CMMFSimpleToneConfig::NewL(TInt aFrequency, const TTimeIntervalMicroSeconds& aDuration)
{
return STATIC_CAST(CMMFToneConfig*, new(ELeave) CMMFSimpleToneConfig(aFrequency, aDuration));
}
CMMFSimpleToneConfig::CMMFSimpleToneConfig(TInt aFrequency, const TTimeIntervalMicroSeconds& aDuration) :
CMMFToneConfig(CMMFToneConfig::EMmfToneTypeSimple),
iFrequency(aFrequency),
iDuration(aDuration)
{
}
CMMFSimpleToneConfig::~CMMFSimpleToneConfig()
{
}
TInt CMMFSimpleToneConfig::Frequency()
{
return iFrequency;
}
const TTimeIntervalMicroSeconds& CMMFSimpleToneConfig::Duration()
{
return iDuration;
}
// Dual Tone
CMMFToneConfig* CMMFDualToneConfig::NewL(TInt aFrequencyOne, TInt aFrequencyTwo, const TTimeIntervalMicroSeconds& aDuration)
{
return STATIC_CAST(CMMFToneConfig*, new(ELeave) CMMFDualToneConfig(aFrequencyOne, aFrequencyTwo, aDuration));
}
CMMFDualToneConfig::CMMFDualToneConfig(TInt aFrequencyOne, TInt aFrequencyTwo, const TTimeIntervalMicroSeconds& aDuration) :
CMMFToneConfig(CMMFToneConfig::EMmfToneTypeDual),
iFrequencyOne(aFrequencyOne),
iFrequencyTwo(aFrequencyTwo),
iDuration(aDuration)
{
}
CMMFDualToneConfig::~CMMFDualToneConfig()
{
}
TInt CMMFDualToneConfig::FrequencyOne()
{
return iFrequencyOne;
}
TInt CMMFDualToneConfig::FrequencyTwo()
{
return iFrequencyTwo;
}
const TTimeIntervalMicroSeconds& CMMFDualToneConfig::Duration()
{
return iDuration;
}
CMMFToneConfig* CMMFDTMFStringToneConfig::NewL(const TDesC& aDTMF)
{
CMMFDTMFStringToneConfig* s = new(ELeave) CMMFDTMFStringToneConfig;
CleanupStack::PushL(s);
s->ConstructL(aDTMF);
CleanupStack::Pop();
return STATIC_CAST(CMMFToneConfig*, s);
}
CMMFDTMFStringToneConfig::CMMFDTMFStringToneConfig() :
CMMFToneConfig(CMMFToneConfig::EMmfToneTypeDTMF)
{
}
LOCAL_C void validateDTMFL(const TDesC& aDTMF)
//
// Validate that the supplied DTMf string contains only playable characters
//
{
TInt stringLength = aDTMF.Length();
TChar ch;
for (TInt index = 0; index < stringLength ; index++)
{
ch = aDTMF[index];
if (!ch.IsDigit() && !ch.IsHexDigit() && !ch.IsSpace() &&
(ch != '*') && (ch != '#') && (ch != ','))
{
User::Leave(KErrArgument); // Bad DTMF string
}
}
}
void CMMFDTMFStringToneConfig::ConstructL(const TDesC& aDTMF)
{
validateDTMFL(aDTMF);
iDTMF = aDTMF.AllocL();
}
CMMFDTMFStringToneConfig::~CMMFDTMFStringToneConfig()
{
delete iDTMF;
}
const TDesC& CMMFDTMFStringToneConfig::DTMF()
{
return *iDTMF;
}
CMMFToneConfig* CMMFDesSeqToneConfig::NewL(const TDesC8& aDesSeq)
{
CMMFDesSeqToneConfig* s = new(ELeave) CMMFDesSeqToneConfig;
CleanupStack::PushL(s);
s->ConstructL(aDesSeq);
CleanupStack::Pop();
return STATIC_CAST(CMMFToneConfig*, s);
}
CMMFDesSeqToneConfig::CMMFDesSeqToneConfig() :
CMMFToneConfig(CMMFToneConfig::EMmfToneTypeDesSeq)
{
}
void CMMFDesSeqToneConfig::ConstructL(const TDesC8& aDesSeq)
{
iDesSeq = aDesSeq.AllocL();
}
CMMFDesSeqToneConfig::~CMMFDesSeqToneConfig()
{
delete iDesSeq;
}
const TDesC8& CMMFDesSeqToneConfig::DesSeq()
{
return *iDesSeq;
}
CMMFToneConfig* CMMFFileSeqToneConfig::NewL(const TDesC& aFileSeq)
{
CMMFFileSeqToneConfig* s = new(ELeave) CMMFFileSeqToneConfig;
CleanupStack::PushL(s);
s->ConstructL(aFileSeq);
CleanupStack::Pop();
return STATIC_CAST(CMMFToneConfig*, s);
}
CMMFFileSeqToneConfig::CMMFFileSeqToneConfig() :
CMMFToneConfig(CMMFToneConfig::EMmfToneTypeFileSeq)
{
}
void CMMFFileSeqToneConfig::ConstructL(const TDesC& aFileSeq)
{
// get access to DRM content through filename
iCAFContent = CContent::NewL(aFileSeq);
// open the CAF source with play intent
iCAFData = iCAFContent->OpenContentL(ContentAccess::EPlay, KDefaultContentObject);
// read into a descriptor
TInt dataSize = 0;
iCAFData->DataSizeL(dataSize);
iDesSeq = HBufC8::NewL(dataSize);
TPtr8 desSeqPtr = iDesSeq->Des();
iCAFData->Read(desSeqPtr);
}
CMMFToneConfig* CMMFFileSeqToneConfig::NewL(RFile& aFile)
{
CMMFFileSeqToneConfig* s = new(ELeave) CMMFFileSeqToneConfig;
CleanupStack::PushL(s);
s->ConstructL(aFile);
CleanupStack::Pop();
return STATIC_CAST(CMMFToneConfig*, s);
}
void CMMFFileSeqToneConfig::ConstructL(RFile& aFile)
{
// get DRM access to file handle
iCAFContent = CContent::NewL(aFile);
// open the CAF source with play intent
iCAFData = iCAFContent->OpenContentL(ContentAccess::EPlay, KDefaultContentObject);
// read into a descriptor
TInt dataSize = 0;
iCAFData->DataSizeL(dataSize);
iDesSeq = HBufC8::NewL(dataSize);
TPtr8 desSeqPtr = iDesSeq->Des();
iCAFData->Read(desSeqPtr);
}
CMMFFileSeqToneConfig::~CMMFFileSeqToneConfig()
{
delete iCAFData;
iCAFData = NULL;
delete iCAFContent;
iCAFContent = NULL;
delete iDesSeq;
}
const TDesC8& CMMFFileSeqToneConfig::FileSeq()
{
return *iDesSeq;
}
void CMMFFileSeqToneConfig::ExecuteIntentL()
{
if (iCAFData)
{
User::LeaveIfError(iCAFData->ExecuteIntent(ContentAccess::EPlay));
}
}
CMMFToneConfig* CMMFFixedSeqToneConfig::NewL(TInt aSeqNo)
{
return STATIC_CAST(CMMFToneConfig*, new(ELeave) CMMFFixedSeqToneConfig(aSeqNo));
}
CMMFFixedSeqToneConfig::CMMFFixedSeqToneConfig(TInt aSeqNo) :
CMMFToneConfig(CMMFToneConfig::EMmfToneTypeFixedSeq),
iSequenceNumber(aSeqNo)
{
}
CMMFFixedSeqToneConfig::~CMMFFixedSeqToneConfig()
{
}
TInt CMMFFixedSeqToneConfig::SequenceNumber()
{
return iSequenceNumber;
}