--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tactilefeedback/tactilefeedbackresolver/plugins/tactileaudioplugin/src/tactileaudioplayer.cpp Thu Dec 17 08:53:38 2009 +0200
@@ -0,0 +1,690 @@
+/*
+* Copyright (c) 2007 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: Class for producing audio feedback.
+* Part of: Tactile Feedback.
+*
+*/
+
+
+#include <e32debug.h>
+
+#include <centralrepository.h>
+#include <ecom/implementationproxy.h>
+
+#include <audiopreference.h>
+#include <mda/common/audio.h>
+#include <mdaaudiooutputstream.h>
+
+#include "tactilefeedbackprivatecrkeys.h"
+#include "tactilefeedbacktrace.h"
+
+#include "tactileaudioplayer.h"
+#include "OstTraceDefinitions.h"
+#ifdef OST_TRACE_COMPILER_IN_USE
+#include "tactileaudioplayerTraces.h"
+#endif
+
+const TInt KRiffHeaderSize = 44;
+_LIT8( KRiff, "RIFF" );
+_LIT8( KWave, "WAVE" );
+_LIT8( KFmt, "fmt " );
+_LIT8( KData, "data" );
+
+// ---------------------------------------------------------------------------
+// Constructor.
+// ---------------------------------------------------------------------------
+//
+CTactileAudioPlayer::CTactileAudioPlayer( CRepository& aRepository ):
+ iRepository( aRepository )
+ {
+ }
+
+// ---------------------------------------------------------------------------
+// 2nd phase constructor.
+// ---------------------------------------------------------------------------
+//
+void CTactileAudioPlayer::ConstructL()
+ {
+ TRACE("CTactileAudioPlayer::ConstructL()");
+
+ ReadSettingsL();
+
+ CreateWavPlayerL();
+
+ iCenRepNotifier = CCenRepNotifyHandler::NewL( *this,
+ iRepository,
+ CCenRepNotifyHandler::EIntKey,
+ KTactileFeedbackAudioVolume );
+ iCenRepNotifier->StartListeningL();
+
+ TRACE("CTactileAudioPlayer::ConstructL() - end");
+ }
+
+// ---------------------------------------------------------------------------
+// 2-phased constructor.
+// ---------------------------------------------------------------------------
+//
+CTactileAudioPlayer* CTactileAudioPlayer::NewL( CRepository& aRepository )
+ {
+ CTactileAudioPlayer* self =
+ new ( ELeave ) CTactileAudioPlayer( aRepository );
+ CleanupStack::PushL( self );
+ self->ConstructL( );
+ CleanupStack::Pop( self );
+ return self;
+ }
+
+// ---------------------------------------------------------------------------
+// Destructor.
+// ---------------------------------------------------------------------------
+//
+CTactileAudioPlayer::~CTactileAudioPlayer()
+ {
+ if ( iAudioPlayer )
+ {
+ iAudioPlayer->Stop();
+ delete iAudioPlayer;
+ }
+
+ delete iCenRepNotifier;
+ delete iSensitiveSample;
+ delete iBasicSample;
+ delete iSensitiveFileName;
+ delete iBasicFileName;
+
+ iVolumeLevels.Close();
+ }
+
+
+// ---------------------------------------------------------------------------
+// From class CTactilePlayer
+//
+// Currently we only select volume level according to logical feedback type
+// (i.e. the .wav -file cannot be selected separately for each logical
+// feedback type).
+//
+// We don't do anything in case volume level has been set to zero for the
+// given feedback type (this way e.g. dragging feedback can be disabled
+// totally if that is wanted).
+//
+// Notice that currently the ETouchFeedbackSensitive -feedback is a bit
+// troublesome: Even though we have our own thread for feedback playing,
+// it still lags behind when something is dragged on screen. Final solution
+// may be to configure audio .wav dragging feedback OFF, and use audio
+// tone for dragging instead.
+// ---------------------------------------------------------------------------
+//
+TInt CTactileAudioPlayer::PlayFeedback( TTouchLogicalFeedback aFeedback )
+ {
+ TRACE2( "CTactileAudioPlayer::PlayFeedback( %d )", aFeedback );
+ TInt volumeIndex(0);
+
+ switch ( aFeedback )
+ {
+ case ETouchFeedbackBasic: // flow through
+ case ETouchFeedbackBasicButton: // flow through
+ case ETouchFeedbackList: // flow through
+ case ETouchFeedbackBoundaryList: // flow through
+ case ETouchFeedbackSlider: // flow through
+ case ETouchFeedbackEdit: // flow through
+ case ETouchFeedbackSensitiveInput:
+ case ETouchFeedbackLineSelection: // flow through
+ case ETouchFeedbackBlankSelection: // flow through
+ case ETouchFeedbackTextSelection: // flow through
+ case ETouchFeedbackEmptyLineSelection: // flow through
+ case ETouchFeedbackTab: // flow through
+ case ETouchFeedbackPopUp: // flow through
+ case ETouchFeedbackIncreasingPopUp: // flow through
+ case ETouchFeedbackDecreasingPopUp: // flow through
+ case ETouchFeedbackFlick: // flow through
+ case ETouchFeedbackCheckbox: // flow through
+ case ETouchFeedbackCharacterInputButton:
+ case ETouchFeedbackMultiTouchRecognized:
+ volumeIndex = 0;
+ break;
+ case ETouchFeedbackSensitive: // flow through
+ case ETouchFeedbackSensitiveButton: // flow through
+ case ETouchFeedbackSensitiveList:
+ volumeIndex = 1;
+ break;
+ default:
+ // should not be there at all
+ TRACE2( "CTactileAudioPlayer::PlayFeedback - %d is not a feedback type - returning", aFeedback );
+ break;
+ }
+
+
+ if ( volumeIndex <= iVolumeLevels.Count() &&
+ iVolumeLevels[volumeIndex] > 0 &&
+ iAudioPlayer )
+ {
+ switch ( iState )
+ {
+ case ETactileAudioInitialising:
+ // can't play anything yet
+ break;
+ case ETactileAudioPlaying: // fall trough
+ case ETactileAudioReady:
+ OstTrace1( TACTILE_PERFORMANCE, TACTILE_PLAY_AUDIO_FEEDBACK_1,
+ "e_TACTILE_PLAY_AUDIO_FEEDBACK 1 0x%x", aFeedback );
+
+ if ( aFeedback == ETouchFeedbackBasic )
+ {
+ TRAP_IGNORE( iAudioPlayer->WriteL( *iBasicSample ) );
+ }
+ else
+ {
+ TRAP_IGNORE( iAudioPlayer->WriteL( *iSensitiveSample ) );
+ }
+ OstTrace1( TACTILE_PERFORMANCE, TACTILE_PLAY_AUDIO_FEEDBACK_0,
+ "e_TACTILE_PLAY_AUDIO_FEEDBACK 0 0x%x", aFeedback );
+ iState = ETactileAudioPlaying;
+ break;
+ case ETactileAudioError:
+ break;
+ default:
+ // should not be here
+ TRACE("CTactileAudioPlayer::PlayFeedback - error with audio device");
+ break;
+
+ }
+
+ }
+ else
+ {
+ if ( !iAudioPlayer )
+ {
+ TRACE("CTactileAudioPlayer::PlayFeedback - iAudioPlayer is NULL!");
+ }
+ else
+ {
+ TRACE("CTactileAudioPlayer::PlayFeedback - volume levels not ok");
+ }
+ }
+ TRACE2( "CTactileAudioPlayer::PlayFeedback( %d ) - end", aFeedback );
+ return KErrNone;
+ }
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+TInt CTactileAudioPlayer::PlayPreviewFeedback( TInt aLevel,
+ TTouchLogicalFeedback aFeedback )
+ {
+ TRACE("CTactileAudioPlayer::PlayPreviewFeedback - Begin");
+ TInt ret( KErrArgument );
+
+ iOriginalVolume = iCurrentVolume;
+ iCurrentVolume = aLevel;
+ iAudioPlayer->SetVolume( ScaledVolume() );
+ ret = PlayFeedback( aFeedback );
+ iCurrentVolume = iOriginalVolume;
+ iAudioPlayer->SetVolume( ScaledVolume() );
+
+ TRACE("CTactileAudioPlayer::PlayPreviewFeedback - End");
+ return ret;
+ }
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+void CTactileAudioPlayer::MaoscOpenComplete( TInt aError )
+ {
+ if ( aError == KErrNone )
+ {
+ iCurrentVolume = iVolumeLevels[0];
+ iMaxRawVolume = iAudioPlayer->MaxVolume();
+ iRepository.Get( KTactileFeedbackAudioVolume, iCurrentVolume );
+ iAudioPlayer->SetVolume( ScaledVolume() );
+ TRAP_IGNORE( iAudioPlayer->SetDataTypeL( KMMFFourCCCodePCM16 ) );
+ iState = ETactileAudioReady;
+ }
+ else
+ {
+ TRACE2("CTactileAudioPlayer::MaoscOpenComplete( %d ) failed, will not play feedback", aError );
+ delete iAudioPlayer;
+ iAudioPlayer = NULL;
+
+ iState = ETactileAudioError;
+ }
+ }
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+void CTactileAudioPlayer::MaoscPlayComplete( TInt aError )
+ {
+ TRACE("CTactileAudioPlayer::MaoscPlayComplete - Begin");
+ iAudioPlayer->Stop();
+ if ( aError == KErrCorrupt )
+ {
+ TRACE2("CTactileAudioPlayer::MaoscPlayComplete( %d ) failed, will not play feedback", aError );
+ delete iAudioPlayer;
+ iAudioPlayer = NULL;
+
+ iState = ETactileAudioError;
+ }
+ else
+ {
+ iState = ETactileAudioReady;
+ }
+ TRACE("CTactileAudioPlayer::MaoscPlayComplete - End");
+ }
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+void CTactileAudioPlayer::MaoscBufferCopied( TInt aError, const TDesC8& /*aBuffer*/ )
+ {
+ if ( !aError )
+ {
+ iState = ETactileAudioReady; // may write another sample
+ }
+ else
+ {
+ TRACE2("CTactileAudioPlayer::MaoscPlayComplete( %d ) failed", aError);
+ }
+ }
+
+// ---------------------------------------------------------------------------
+// Settings are now not read completely, as only the .wav -file of basic
+// feedback is read, and same file is used for sensitive feedback.
+// Using of separate files for basic and sensitive feedback
+// can be added later in case necessary.
+// ---------------------------------------------------------------------------
+//
+void CTactileAudioPlayer::ReadSettingsL()
+ {
+ TRACE("CTactileAudioPlayer::ReadSettingsL - Begin");
+
+ iVolumeLevels.Reset();
+
+ delete iSensitiveFileName;
+ iSensitiveFileName = NULL;
+
+ delete iBasicFileName;
+ iBasicFileName = NULL;
+
+ iSensitiveFileName = HBufC::NewL( KMaxFileName );
+ TPtr sensitiveFileName = iSensitiveFileName->Des();
+
+ iBasicFileName = HBufC::NewL( KMaxFileName );
+ TPtr basicFileName = iBasicFileName->Des();
+
+ TInt basicVolumeLevel = 0;
+ TInt sensitiveVolumeLevel = 0;
+
+ // Read volume values for level 2
+ iRepository.Get( KTactileAudioWavVolumeBasicLevel2, basicVolumeLevel );
+
+
+ iRepository.Get( KTactileAudioWavVolumeSensitiveLevel2, sensitiveVolumeLevel );
+
+ // Read file names
+ iRepository.Get( KTactileAudioWavFileBasicLevel2, basicFileName );
+
+ iRepository.Get( KTactileAudioWavFileSensitiveLevel2, sensitiveFileName );
+
+ iVolumeLevels.Append( basicVolumeLevel );
+ iVolumeLevels.Append( sensitiveVolumeLevel );
+
+ TRACE("CTactileAudioPlayer::ReadSettingsL() - End");
+ }
+
+
+// ---------------------------------------------------------------------------
+// ScaledVolume()
+// return 100% scaled & sanity checked volume value
+// ---------------------------------------------------------------------------
+//
+TInt CTactileAudioPlayer::ScaledVolume()
+ {
+ if ( iMaxRawVolume == KErrNotFound )
+ {
+ TRACE( "CTactileAudioPlayer::ScaledVolume() Audio Hardware is not initialized properly" );
+ return 0;
+ }
+
+ TInt volume = iMaxRawVolume * iCurrentVolume / 100;
+
+ if ( volume > iMaxRawVolume )
+ {
+ // sanity check, we might get anything from cenrep
+ volume = iMaxRawVolume;
+ }
+
+ TRACE4( "CTactileAudioPlayer::ScaledVolume() iCurrentVolume:%d scales volume to:%d out of iMaxRawVolume:%d",
+ iCurrentVolume, volume, iMaxRawVolume );
+
+ return volume;
+ }
+
+/*
+* Wave file structure: Riff header + Wave format chunk + Wave data chunk
+*
+* Riff header:
+* ==================================================
+* Offset Size Description Value
+* 0x00 4 Chunk ID "RIFF"
+* 0x04 4 Chunk Data Size ( file size ) - 8
+* 0x08 4 RIFF Type "WAVE"
+* 0x0c * Wave chunks *
+*
+* Wave Format Chunk:
+* ==================================================
+* Offset Size Description Value
+* 0x00 4 Chunk ID "fmt "
+* 0x04 4 Chunk Data Size 16 + extra format bytes ( 0 for normal wav files)
+* 0x08 2 Compression code 1...65535 ( 1 for PCM uncompressed)
+* 0x0a 2 Nbr of channels 1...65535
+* 0x0c 4 Sample rate 1...0xFFFFFFFF
+* 0x10 4 Average bytes per sec
+* 0x14 2 block align
+* 0x16 2 siginificant bits per sample
+* 0x18 2 extra format bytes 0...65535
+* 0x1a * extra format bytes, if any *
+*
+* Wave Data Chunk:
+* ==================================================
+* Offset Size Description Value
+* 0x00 4 Chunk ID "data"
+* 0x04 4 Chunk data size
+* 0x08 * sample data *
+*
+*/
+void CTactileAudioPlayer::ReadSampleL( RFile& aFile,
+ HBufC8*& aDes,
+ TUint& aChannels,
+ TUint& aSampleRate )
+ {
+ TRACE("CTactileAudioPlayer::ReadSampleL - Start");
+ const TInt fmtOffset = 0x0c;
+ const TInt dataOffset = fmtOffset + 0x18;
+
+ TBuf8<KRiffHeaderSize> header;
+ TInt err = aFile.Read( header, KRiffHeaderSize );
+ if ( err )
+ {
+ TRACE("CTactileAudioPlayer::ReadSampleL: reading from file failed, aborting");
+ User::Leave( err );
+ }
+
+ TPtr8 p = header.LeftTPtr( 4 );
+
+ if ( p.Compare( KRiff ) )
+ {
+ TRACE("CTactileAudioPlayer::ReadSampleL: no RIFF header found, aborting" );
+ User::Leave( KErrCorrupt );
+ }
+
+ p = header.MidTPtr( 0x08, 4 );
+ if ( p.Compare( KWave ) )
+ {
+ TRACE("CTactileAudioPlayer::ReadSampleL: not a WAVE file, aborting" );
+ User::Leave( KErrCorrupt );
+ }
+
+ p = header.MidTPtr( fmtOffset + 0x00, 4 );
+ if ( p.Compare( KFmt ) )
+ {
+ TRACE("CTactileAudioPlayer::ReadSampleL: no 'fmt ' chunk found, aborting" );
+ User::Leave( KErrCorrupt );
+ }
+
+ p = header.MidTPtr( dataOffset, 4 );
+ if ( p.Compare( KData ) )
+ {
+ TRACE("CTactileAudioPlayer::ReadSampleL: no 'data' chunk found, aborting" );
+ User::Leave( KErrCorrupt );
+ }
+
+ TUint8 lo = header[ fmtOffset + 0x08 ];
+ TUint8 hi = header[ fmtOffset + 0x08 + 1 ];
+ if ( !( lo == 1 && hi == 0) )
+ {
+ TRACE("CTactileAudioPlayer::ReadSampleL: non PCM wav not supported, aborting" );
+ User::Leave( KErrNotSupported );
+ }
+
+ lo = header[ fmtOffset + 0x0a ];
+ hi = header[ fmtOffset + 0x0a + 1 ];
+ aChannels = lo;
+ if ( !(aChannels == 1 || aChannels == 2 && hi == 0) )
+ {
+ TRACE2("CTactileAudioPlayer::ReadSampleL: unsupported number of channels ( %d ), aborting", aChannels );
+ User::Leave( KErrNotSupported );
+ }
+
+ aSampleRate = 0;
+ for ( TInt i = 0; i < 4; i++ )
+ {
+ lo = header[ fmtOffset + 0x0c + i ];
+ TUint32 tmp = lo;
+ tmp = tmp << i * 8;
+
+ aSampleRate = aSampleRate | tmp;
+ }
+
+ lo = header[ fmtOffset + 0x16 ];
+ hi = header[ fmtOffset + 0x16 + 1 ];
+ TUint16 bitsPerSample = hi;
+ bitsPerSample = bitsPerSample << 8;
+ bitsPerSample = bitsPerSample | lo;
+
+ if ( bitsPerSample != 16 )
+ {
+ TRACE2("CTactileAudioPlayer::ReadSampleL: %d bits per sample not supported", bitsPerSample );
+ User::Leave( KErrNotSupported );
+ }
+
+ TUint32 bytesPerSample = bitsPerSample / 8;
+
+ // how many bytes for 6 ms
+ TUint bytesNeeded = ( aSampleRate * aChannels * bytesPerSample * 6 ) / 1000;
+
+ TInt fsize( 0 );
+ if ( aFile.Size( fsize ) == KErrNone && fsize >= bytesNeeded + KRiffHeaderSize )
+ {
+ aDes = HBufC8::NewL( bytesNeeded );
+ TPtr8 des = aDes->Des();
+ aFile.Read( des, bytesNeeded );
+ }
+ else
+ {
+ TRACE("CTactileAudioPlayer::ReadSampleL: Less than 6ms content in file, aborting" );
+ User::Leave( KErrNotSupported );
+ }
+
+ TRACE3("CTactileAudioPlayer::ReadSampleL %dHz %dchannel sample read successfully - End",
+ iSampleRate, iChannels);
+ }
+
+// ---------------------------------------------------------------------------
+// Audio data reading from file and creation of the actual player utility.
+//
+// Rest of the initializations are done in MapcInitComplete -function.
+//
+// Notice that CMdaAudioOutputStream usage is not a good idea, as it
+// buffers samples until buffer is full and flushes all in a row. Result is
+// no feedback first, then a machine gun burst at some completely
+// unrelated moment.
+// ---------------------------------------------------------------------------
+//
+void CTactileAudioPlayer::CreateWavPlayerL()
+ {
+ TRACE("CTactileAudioPlayer::CreateWavPlayerL - Start");
+ iState = ETactileAudioInitialising;
+ delete iBasicSample;
+ iBasicSample = NULL;
+ delete iSensitiveSample;
+ iSensitiveSample = NULL;
+
+ if ( !( iBasicFileName && iBasicFileName->Length() > 0 &&
+ iSensitiveFileName && iSensitiveFileName->Length() > 0 ))
+ {
+ TRACE("CTactileAudioPlayer::CreateWavPlayerL filenames missing, aborting");
+ User::Leave( KErrBadName );
+ }
+
+ RFs fs;
+ User::LeaveIfError ( fs.Connect() );
+ CleanupClosePushL( fs );
+
+ RFile file;
+ TInt err = file.Open( fs, *iBasicFileName, EFileRead );
+ if ( err )
+ {
+ TRACE2("CTactileAudioPlayer::CreateWavPlayerL could not open %S, aborting", iBasicFileName );
+ User::Leave( err );
+ }
+
+ CleanupClosePushL( file );
+ ReadSampleL( file, iBasicSample, iChannels, iSampleRate );
+ CleanupStack::PopAndDestroy(&file);
+
+ RFile file2;
+ err = file2.Open( fs, *iSensitiveFileName, EFileRead );
+ if ( err )
+ {
+ TRACE2("CTactileAudioPlayer::CreateWavPlayerL could not open %S, aborting", iSensitiveFileName );
+ User::Leave( err );
+ }
+
+ CleanupClosePushL( file2 );
+
+ TUint sampleRate(0);
+ TUint channels(0);
+ ReadSampleL( file2, iSensitiveSample, channels, sampleRate );
+ CleanupStack::PopAndDestroy( &file2 );
+ CleanupStack::PopAndDestroy( &fs );
+
+ if ( channels != iChannels || sampleRate != iSampleRate )
+ {
+ TRACE("CTactileAudioPlayer::CreateWavPlayerL Sample rates and number of channels must be same for both files, aborting");
+ User::Leave( KErrNotSupported );
+ }
+
+ TInt priority = KAudioPriorityKeyPressNonDTMFWithFeedback;
+ TMdaPriorityPreference pref = static_cast<TMdaPriorityPreference>(KAudioPrefKeyPressNonDTMFWithFeedback);
+
+ iAudioPlayer = CMdaAudioOutputStream::NewL( *this ,priority, pref);
+
+ TMdaAudioDataSettings streamSettings;
+ switch ( iChannels )
+ {
+ case 1:
+ streamSettings.iChannels = TMdaAudioDataSettings::EChannelsMono;
+ break;
+ case 2:
+ streamSettings.iChannels = TMdaAudioDataSettings::EChannelsStereo;
+ TRACE("CTactileAudioPlayer::CreateWavPlayerL Warning: stereo wav for feedback");
+ break;
+ default:
+ TRACE2("CTactileAudioPlayer::CreateWavPlayerL: unsupported number of channels %d, aborting", iChannels );
+ User::Leave( KErrNotSupported );
+ break;
+ }
+
+ // there must be easier way to do this...
+ switch( iSampleRate )
+ {
+ case 48000:
+ streamSettings.iSampleRate = TMdaAudioDataSettings::ESampleRate48000Hz;
+ streamSettings.iCaps = TMdaAudioDataSettings::ESampleRate48000Hz;
+ break;
+ case 44100:
+ TRACE2("CTactileAudioPlayer::CreateWavPlayerL: warning, samplerate %d causes performance problem", iSampleRate );
+ streamSettings.iSampleRate = TMdaAudioDataSettings::ESampleRate44100Hz;
+ streamSettings.iCaps = TMdaAudioDataSettings::ESampleRate44100Hz;
+ break;
+ case 32000:
+ streamSettings.iSampleRate = TMdaAudioDataSettings::ESampleRate32000Hz;
+ streamSettings.iCaps = TMdaAudioDataSettings::ESampleRate32000Hz;
+ break;
+ case 24000:
+ streamSettings.iSampleRate = TMdaAudioDataSettings::ESampleRate24000Hz;
+ streamSettings.iCaps = TMdaAudioDataSettings::ESampleRate24000Hz;
+ break;
+ case 16000:
+ streamSettings.iSampleRate = TMdaAudioDataSettings::ESampleRate16000Hz;
+ streamSettings.iCaps = TMdaAudioDataSettings::ESampleRate16000Hz;
+ break;
+ case 12000:
+ streamSettings.iSampleRate = TMdaAudioDataSettings::ESampleRate12000Hz;
+ streamSettings.iCaps = TMdaAudioDataSettings::ESampleRate12000Hz;
+ break;
+ case 11025:
+ TRACE2("CTactileAudioPlayer::CreateWavPlayerL: warning, samplerate %d causes performance problem",iSampleRate );
+ streamSettings.iSampleRate = TMdaAudioDataSettings::ESampleRate11025Hz;
+ streamSettings.iCaps = TMdaAudioDataSettings::ESampleRate11025Hz;
+ break;
+ case 8000:
+ streamSettings.iSampleRate = TMdaAudioDataSettings::ESampleRate8000Hz;
+ streamSettings.iCaps = TMdaAudioDataSettings::ESampleRate8000Hz;
+ break;
+ default:
+ TRACE2("CTactileAudioPlayer::CreateWavPlayerL: unsupported samplerate %d, aborting",iSampleRate );
+ User::Leave( KErrNotSupported );
+ break;
+ }
+
+ iAudioPlayer->Open( &streamSettings );
+
+ TRACE("CTactileAudioPlayer::CreateWavPlayerL - End");
+ }
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+void CTactileAudioPlayer::HandleNotifyInt( TUint32 aId, TInt aNewValue )
+ {
+ TRACE("CTactileTonePlayer::HandleNotifyInt - Begin");
+ if ( aId == KTactileFeedbackAudioVolume )
+ {
+ iCurrentVolume = aNewValue;
+ iAudioPlayer->SetVolume( ScaledVolume() );
+ }
+ TRACE("CTactileTonePlayer::HandleNotifyInt - End");
+ }
+
+
+//---------------------------------------------------------------------------
+// ImplementationTable[]
+//
+//---------------------------------------------------------------------------
+//
+const TImplementationProxy ImplementationTable[] =
+ {
+ IMPLEMENTATION_PROXY_ENTRY( 0x2002133A, CTactileAudioPlayer::NewL )
+ };
+
+//---------------------------------------------------------------------------
+// TImplementationProxy* ImplementationGroupProxy()
+//
+//---------------------------------------------------------------------------
+//
+EXPORT_C const TImplementationProxy* ImplementationGroupProxy( TInt& aTableCount )
+ {
+ aTableCount = sizeof(ImplementationTable) / sizeof(TImplementationProxy);
+ return ImplementationTable;
+ }
+
+
+
+// End of file