srsf/devasr/src/devasrsrsalgorithmmanager.cpp
author Pat Downey <patd@symbian.org>
Wed, 01 Sep 2010 12:29:17 +0100
branchRCL_3
changeset 19 e36f3802f733
parent 0 bf1d17376201
permissions -rw-r--r--
Revert incorrect RCL_3 drop: Revision: 201033 Kit: 201035

/*
* Copyright (c) 2004-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:  This file contains the implementation of Algorithm Manager,
*               a submodule of DevASR.
*
*/


// INCLUDE FILES
#include <mmfdatabuffer.h>
#include <AudioPreference.h>
#include <nssdevasr.h>
#include "devasrsrsalgorithmmanager.h"
#include "devasrvmalgorithmmanager.h"
#include "rubydebug.h"
#include "devasrcenrep.h"
#include "srsfbldvariant.hrh"

// CONSTANTS
const TInt KPlay = 1;
const TInt KRecord = KPlay + 1;

// Extra error values
const TInt KErrTooEarly = -100; // if speech was started too early
const TInt KErrNoSpeech = -101; // if it was silent 
const TInt KErrTooLong  = -102; // if speech did not stop before timeout
const TInt KErrTooShort = -103; // if speech was too short

// Default priority for recording
const TInt KDefaultPriority = KAudioPriorityVoiceDial;

// ============================ MEMBER FUNCTIONS ===============================

// -----------------------------------------------------------------------------
// CSRSAlgorithmManager::CSRSAlgorithmManager
// C++ default constructor can NOT contain any code, that
// might leave.
// -----------------------------------------------------------------------------
//
CSRSAlgorithmManager::CSRSAlgorithmManager( MDevASRObserver& aObserver )
                                           : CActive( CActive::EPriorityStandard ),
                                             iDevASRObserver( &aObserver ),
                                             iDevSound( NULL ),
                                             iCurrentVolume( 0 ),
                                             iCurrentGain( 0 ),
                                             iRecognitionAlgMgr( NULL ),
                                             iVMAlgorithmManager( NULL ),
                                             iStartRecognition( EFalse ),
                                             iPendingRequestSpeechData( EFalse ),
                                             iStartPoint( 0 ),
                                             iStopPoint( 0 ),
                                             iAudioBuffer( NULL ),
                                             iPtr( NULL, 0, 0 ),
                                             iOverallLength( 0 ),
                                             iOverallSampled( 0 ),
                                             iProcessingUtterance( EFalse ),
                                             iEndFlag( 0 ),
                                             iStartFrame( 0 ),
                                             iEndFrame( 0 ),
                                             iFrameLength( 0 ),
                                             iBufferStartPoint( 0 ),
                                             iBufferEndPoint( 0 ),
                                             iDevASRState( EDASRIdle ),
                                             iDevSoundState( ESoundDeviceNotInitialized ),
                                             iRequestFunction( 0 ),
                                             iBufferUnderConstruction( NULL ),
                                             iConstructionPoint( 0 ),
                                             iPreSamplingStarted( EFalse )
    {
    RUBY_DEBUG0( "CSRSAlgorithmManager::CSRSAlgorithmManager()" );
#ifdef AUDIOBUFFER_TO_FILE
    iFileCreated = EFalse;
#endif

    }


// -----------------------------------------------------------------------------
// CSRSAlgorithmManager::ConstructL
// Symbian 2nd phase constructor can leave.
// -----------------------------------------------------------------------------
//
void CSRSAlgorithmManager::ConstructL()
    {
    RUBY_DEBUG_BLOCK( "CSRSAlgorithmManager::ConstructL()" );

    // Resource handler reads the DevASR resource file
    iResourceHandler = CDevASRResourceHandler::NewL();

    iRecognitionAlgMgr = CRecognitionAlgMgr::NewL( *this );
    iVMAlgorithmManager = CVMAlgorithmManager::NewL( *iDevASRObserver, *this );

    // Queue containing audio buffers
    iAudioBufferQue = new ( ELeave ) TSglQue<CQueItem>( _FOFF( CQueItem, iLink ) );

    // Set default priority settings
    iPrioritySettings.iState = EMMFStateRecording;
    iPrioritySettings.iPriority = KDefaultPriority;
    iPrioritySettings.iPref = ( TMdaPriorityPreference ) KAudioPrefVocosRecog;

    // CenRep utility class
    CDevAsrCenRep* cenRep = CDevAsrCenRep::NewL();
    CleanupStack::PushL( cenRep );
    
    iRecognitionAlgMgr->SetRejection( cenRep->RejectionValue() );
    
    CleanupStack::PopAndDestroy( cenRep );

    CActiveScheduler::Add( this );

    RUBY_DEBUG1( "associated DevSound instance [%x]", iDevSound );
    RUBY_DEBUG1( "associated Recognition AlgMgr instance [%x]", iRecognitionAlgMgr );
    RUBY_DEBUG1( "associated Vocabulary AlgMgr instance [%x]", iRecognitionAlgMgr );
    }


// -----------------------------------------------------------------------------
// CSRSAlgorithmManager::NewL
// Two-phased constructor.
// -----------------------------------------------------------------------------
//
CSRSAlgorithmManager* CSRSAlgorithmManager::NewL( MDevASRObserver& aObserver )
    {
    CSRSAlgorithmManager* self = new( ELeave ) CSRSAlgorithmManager( aObserver );

    CleanupStack::PushL( self );
    self->ConstructL();
    CleanupStack::Pop( self );

    return self;
    }


// -----------------------------------------------------------------------------
// CSRSAlgorithmManager::~CSRSAlgorithmManager
// Destructor.
// -----------------------------------------------------------------------------
//
CSRSAlgorithmManager::~CSRSAlgorithmManager()
    {
    RUBY_DEBUG0( "CSRSAlgorithmManager::~CSRSAlgorithmManager()" );

    //delete iAudioBuffer;
    delete iQueItem;

    // Empty audio queue if there happens to be something
    if ( iAudioBufferQue )
        {
        while ( !iAudioBufferQue->IsEmpty() )
            {
            iQueItem = iAudioBufferQue->First();
            iAudioBufferQue->Remove( *iQueItem );
            delete iQueItem;
            }

        delete iAudioBufferQue;
        }

    delete iBufferUnderConstruction;
    iBufferUnderConstruction = NULL;
    iConstructionPoint = 0;

    delete iDevSound;
    delete iRecognitionAlgMgr;
    delete iVMAlgorithmManager;
    delete iResourceHandler;
    }


// -----------------------------------------------------------------------------
// CSRSAlgorithmManager::AdaptL
// Adapts vocabulary and models based on correct result.
// -----------------------------------------------------------------------------
//
void CSRSAlgorithmManager::AdaptL( const CSIResultSet& aResultSet, 
                                   TInt aResultIndex )
    {
    RUBY_DEBUG_BLOCK( "CSRSAlgorithmManager::AdaptL()" );

    // Adapt vocab
    iVMAlgorithmManager->AdaptVocabL( aResultSet, aResultIndex );

    // Find language of correct result
    const CSIResult& iCorrectResult = aResultSet.AtL( aResultIndex );
    TSIGrammarID grammarID = iCorrectResult.GrammarID();
    TSIRuleID ruleID = iCorrectResult.RuleID();
    TSIRuleVariantID ruleVariantID = iCorrectResult.RuleVariantID();
    CSICompiledGrammar* siActiveGrammar = NULL;
    CSICompiledGrammar* siNonActiveGrammar = NULL;
    CSICompiledGrammar* siGrammar = NULL;
  
    TRAPD( error, GetGrammarL( grammarID, &siActiveGrammar, &siNonActiveGrammar ) );
    User::LeaveIfError( error );

    TInt index = 0;

    if ( siActiveGrammar != NULL )
        {
        siGrammar = siActiveGrammar;
        }
    else if ( siNonActiveGrammar != NULL )
        {
        siGrammar = siNonActiveGrammar;
        }
    else
        {
        User::Leave( KErrNotFound );	
        }
    
    index = siGrammar->Find( ruleID );
    User::LeaveIfError( index );
    CSIRule& rule = siGrammar->AtL( index );

    index = rule.Find( ruleVariantID );
    User::LeaveIfError( index );
    CSIRuleVariant& ruleVariant = rule.AtL( index );

    // Adapt models
    iRecognitionAlgMgr->AdaptModelsL( aResultSet, aResultIndex, ruleVariant.Language() );
    }


// -----------------------------------------------------------------------------
// CSRSAlgorithmManager::CompileGrammarL
// Forward call to CVMAlgorithmManager.
// -----------------------------------------------------------------------------
//
void CSRSAlgorithmManager::CompileGrammarL( CSICompiledGrammar& aGrammar/*,
                                            CSIModelBank& aModelBank*/ )
    {
    RUBY_DEBUG_BLOCK( "CSRSAlgorithmManager::CompileGrammarL()" );

    iVMAlgorithmManager->CompileGrammarL( aGrammar/*, aModelBank*/ );
    }


// -----------------------------------------------------------------------------
// CSRSAlgorithmManager::ComputeNewGrammarSizeL
// Forward call to CVMAlgorithmManager.
// -----------------------------------------------------------------------------
//
void CSRSAlgorithmManager::ComputeNewGrammarSizeL( const CSIGrammar& aGrammar, 
                                                   const TUint32 aTargetNRuleVariants, 
                                                   const TUint32 aMaxNRuleVariants, 
                                                   const RArray<TUint>& aNewRuleScores, 
                                                   RArray<TUint>& aNNeNRuleVariants, 
                                                   TUint32& aNPrune )
    {
    RUBY_DEBUG_BLOCK( "CSRSAlgorithmManager::ComputeNewGrammarSizeL()" );

    iVMAlgorithmManager->ComputeNewGrammarSizeL( aGrammar,
                                                 aTargetNRuleVariants,
                                                 aMaxNRuleVariants,
                                                 aNewRuleScores,
                                                 aNNeNRuleVariants,
                                                 aNPrune );
    }


// -----------------------------------------------------------------------------
// CSRSAlgorithmManager::PruneGrammar
// Forward call to CVMAlgorithmManager.
// -----------------------------------------------------------------------------
//
TBool CSRSAlgorithmManager::PruneGrammar( const CSIGrammar& aGrammar, 
                                          const TUint32 aMinNumber, 
                                          RArray<TSIRuleVariantInfo>& aPrunedRuleVariants )
    {
    return iVMAlgorithmManager->PruneGrammar( aGrammar, aMinNumber, aPrunedRuleVariants );
    }


// -----------------------------------------------------------------------------
// CSRSAlgorithmManager::StartTrainingFromTextL
// Forward call to CVMAlgorithmManager.
// -----------------------------------------------------------------------------
// 
void CSRSAlgorithmManager::StartTrainingFromTextL( CSITtpWordList& aWordList, 
                                                   const RArray<TLanguage>& aDefaultLanguage, 
                                                   const RArray<TUint32>& aMaxNPronunsForWord )
    {
    RUBY_DEBUG_BLOCK( "CSRSAlgorithmManager::StartTrainingFromTextL()" );

    iVMAlgorithmManager->TrainFromTextL( aWordList, aDefaultLanguage, aMaxNPronunsForWord );
    }


// -----------------------------------------------------------------------------
// CSRSAlgorithmManager::ResolveResult
// Forward call to CVMAlgorithmManager.
// -----------------------------------------------------------------------------
// 
void CSRSAlgorithmManager::ResolveResult( const RArray<TUint>& aNBestIDs,
                                          CSIResultSet& aSIResultSet,
                                          const RPointerArray<CSICompiledGrammar>& aSICompiledGrammar,
                                          const TDesC8& aCombinedData/*,
                                          CSIModelBank& iSIModelBank*/ )
    {
    iVMAlgorithmManager->ResolveResult( aNBestIDs, aSIResultSet, 
                                        aSICompiledGrammar, aCombinedData/*,
                                        iSIModelBank*/ );
    }


// -----------------------------------------------------------------------------
// CSRSAlgorithmManager::CombineGrammarL
// Forward call to CVMAlgorithmManager.
// -----------------------------------------------------------------------------
// 
void CSRSAlgorithmManager::CombineGrammarL( const RPointerArray<CSICompiledGrammar>& aCompiledGrammars,
                                            const RPointerArray<TSIRuleVariantInfo>& aExcludedRules )
    {
    RUBY_DEBUG_BLOCK( "CSRSAlgorithmManager::CombineGrammarL()" );

    iVMAlgorithmManager->CombineGrammarL( aCompiledGrammars, aExcludedRules );
    }


// -----------------------------------------------------------------------------
// CSRSAlgorithmManager::ConfigureSoundDeviceL
// Configure sound device according to resource file parameters
// -----------------------------------------------------------------------------
//
void CSRSAlgorithmManager::ConfigureSoundDeviceL()
    {
    RUBY_DEBUG_BLOCK( "CSRSAlgorithmManager::ConfigureSoundDeviceL()" );

	// Fetch the default configuration from DevSound
    iDevSoundCapabilities = iDevSound->Config();

	// Now, configure it according to resource file parameters
    switch ( iResourceHandler->iSamplingRate )
		{
		case 8000:
			iDevSoundCapabilities.iRate = EMMFSampleRate8000Hz;
			break;
		case 11025:
			iDevSoundCapabilities.iRate = EMMFSampleRate11025Hz;
			break;
		case 16000:
			iDevSoundCapabilities.iRate = EMMFSampleRate16000Hz;
			break;
		case 22050:
			iDevSoundCapabilities.iRate = EMMFSampleRate22050Hz;
			break;
		case 32000:
			iDevSoundCapabilities.iRate = EMMFSampleRate32000Hz;
			break;
		case 44100:
			iDevSoundCapabilities.iRate = EMMFSampleRate44100Hz;
			break;
		case 48000:
			iDevSoundCapabilities.iRate = EMMFSampleRate48000Hz;
			break;
		case 88200:
			iDevSoundCapabilities.iRate = EMMFSampleRate88200Hz;
			break;
		case 96000:
			iDevSoundCapabilities.iRate = EMMFSampleRate96000Hz;
			break;
		default:
			iDevSoundCapabilities.iRate = EMMFSampleRate8000Hz;
			break;
		}

    iDevSoundCapabilities.iBufferSize = iResourceHandler->iBufferSize;

    if ( iResourceHandler->iBitsPerSample == 8 )
        {
        iDevSoundCapabilities.iEncoding = EMMFSoundEncoding8BitPCM;
        }
    else
        {
        iDevSoundCapabilities.iEncoding = EMMFSoundEncoding16BitPCM;
        }

	// Now, configure DevSound according to new parameters.
    iDevSound->SetConfigL( iDevSoundCapabilities );

    RUBY_DEBUG1( "DevSound Max Volume = %d", iDevSound->MaxVolume() );
    RUBY_DEBUG1( "DevSound Max Gain = %d", iDevSound->MaxGain() );

    // In order to avoid truncation, computation must be done this way.
    iCurrentVolume = ( ( iDevSound->MaxVolume() * iResourceHandler->iSpeakerVolume ) + 50 ) / 100;
    iCurrentGain = ( ( iDevSound->MaxGain() * iResourceHandler->iMicrophoneGain ) + 50 ) / 100;

    // The speaker volume is set to the percentage of max volume supported.
    iDevSound->SetVolume( iCurrentVolume );
    // The gain is set to the percentage of max gain supported.
    iDevSound->SetGain( iCurrentGain );

    iDevSoundCapabilities = iDevSound->Config();

    RUBY_DEBUG1( "DevSound Set Volume = %d", iCurrentVolume );
    RUBY_DEBUG1( "DevSound Set Gain = %d", iCurrentGain );
    RUBY_DEBUG1( "DevSound Buffer Size = %d", iDevSoundCapabilities.iBufferSize );
    }


// -----------------------------------------------------------------------------
// CSRSAlgorithmManager::GetEnginePropertiesL
// Retreive the properties of the underlying speech recognition engine.
// An array of values corresponding to the querried identifiers will be populated.
// The function may leave with KErrArgument.
// -----------------------------------------------------------------------------
//
void CSRSAlgorithmManager::GetEnginePropertiesL( const RArray<TInt>& aPropertyId,
                                                 RArray<TInt>& aPropertyValue )
    {
    RUBY_DEBUG_BLOCK( "SRSAlgorithmManager::EnginePropertiesL()" );

    // Check that arrays are ok
    if ( aPropertyId.Count() != aPropertyValue.Count() )
        {
        User::Leave( KErrArgument );
        }

	// Run through the engine properties and fill in known values
    for ( TInt index = 0; index < aPropertyId.Count(); index++)
        {
        switch( aPropertyId[index] )
            {
            case KSamplingRate:
                aPropertyValue[index] = iResourceHandler->iSamplingRate;
                break;

            case KBitsPerSample:
                aPropertyValue[index] = iResourceHandler->iBitsPerSample;
                break;

            default:
                break;

            }
        }
	// Get engine properties from other sources.
    iRecognitionAlgMgr->GetEnginePropertiesL( aPropertyId, aPropertyValue );
    iVMAlgorithmManager->GetEnginePropertiesL( aPropertyId, aPropertyValue );
    }


// -----------------------------------------------------------------------------
// CSRSAlgorithmManager::InitFrontEnd
// Initializes the recognition front end.
// -----------------------------------------------------------------------------
//
void CSRSAlgorithmManager::InitFrontEnd( TRecognizerMode aMode )
    {
    RUBY_DEBUG0( "CSRSAlgorithmManager::InitFrontEnd()" );

	iProcessingUtterance = EFalse;

    if ( iMode != aMode )
        {
        return;
        }

    StateTransition( EDASRInitRecognition );

    iRecognitionAlgMgr->InitFrontEnd( aMode );
    }


// -----------------------------------------------------------------------------
// CSRSAlgorithmManager::InitRecognizerBE
// Initializes the recognition back-end. The module responsible for recognition
// function is started as a result.
// -----------------------------------------------------------------------------
//
void CSRSAlgorithmManager::InitRecognizerBE( CSIResultSet& aResult )
    {
    RUBY_DEBUG0( "CSRSAlgorithmManager::InitRecognizerBE()" );

    iRecognitionAlgMgr->InitRecognizerBE( aResult );
    }


// -----------------------------------------------------------------------------
// CSRSAlgorithmManager::IsGrammarLoaded
// Checks if grammar has been loaded.
// -----------------------------------------------------------------------------
//
TBool CSRSAlgorithmManager::IsGrammarLoaded( TSIGrammarID aGrammarID )
    {
    CSICompiledGrammar* siActiveGrammar = NULL;
    CSICompiledGrammar* siNonActiveGrammar = NULL;
  
    TRAPD( error, GetGrammarL( aGrammarID, &siActiveGrammar, &siNonActiveGrammar ) );
    if ( error != KErrNone )
        {
        return EFalse;
        }

    if ( siActiveGrammar != NULL )
        {
        return ETrue;
        }
    else if ( siNonActiveGrammar != NULL )
        {
        return ETrue;
        }

    return EFalse;
    }


// -----------------------------------------------------------------------------
// CSRSAlgorithmManager::IsGrammarActive
// Checks if grammar is currently active.
// -----------------------------------------------------------------------------
//
TBool CSRSAlgorithmManager::IsGrammarActive( TSIGrammarID aGrammarID )
    {
    RUBY_DEBUG0( "CSRSAlgorithmManager::IsGrammarActive()" );

    CSICompiledGrammar* siActiveGrammar = NULL;
    CSICompiledGrammar* siNonActiveGrammar = NULL;
  
    TRAPD( error, GetGrammarL( aGrammarID, &siActiveGrammar, &siNonActiveGrammar ) );
    if ( error != KErrNone )
        {
        return EFalse;
        }

    if ( siActiveGrammar != NULL )
        {
        return ETrue;
        }
    else if ( siNonActiveGrammar != NULL )
        {
        return EFalse;
        }

    return EFalse;
    }


// -----------------------------------------------------------------------------
// CSRSAlgorithmManager::LoadGrammarL
// Load the specified grammar into the recognizer.
// -----------------------------------------------------------------------------
//
void CSRSAlgorithmManager::LoadGrammarL( const CSIGrammar& aGrammar )
    {
    RUBY_DEBUG_BLOCK( "CSRSAlgorithmManager::LoadGrammarL(si non-compiled)" );

    iRecognitionAlgMgr->LoadGrammarL( aGrammar );
    }


// -----------------------------------------------------------------------------
// CSRSAlgorithmManager::LoadGrammarL
// Load the specified grammar into the recognizer.
// -----------------------------------------------------------------------------
//
void CSRSAlgorithmManager::LoadGrammarL( const CSICompiledGrammar& aGrammar )
    {
    RUBY_DEBUG_BLOCK( "CSRSAlgorithmManager::LoadGrammarL(si compiled)" );

    iRecognitionAlgMgr->LoadGrammarL( aGrammar );
    }


// -----------------------------------------------------------------------------
// CSRSAlgorithmManager::LoadGrammarL
// Unloads the specified grammar from the recognizer.
// -----------------------------------------------------------------------------
//
void CSRSAlgorithmManager::UnloadGrammarL( const CSIGrammar& aGrammar )
    {
    RUBY_DEBUG_BLOCK( "CSRSAlgorithmManager::UnloadGrammarL(si non-compiled)" );

    iRecognitionAlgMgr->UnloadGrammarL( aGrammar );
    }


// -----------------------------------------------------------------------------
// CSRSAlgorithmManager::UnloadGrammarL
// Unloads the specified grammar from the recognizer.
// -----------------------------------------------------------------------------
//
void CSRSAlgorithmManager::UnloadGrammarL( const CSICompiledGrammar& aGrammar )
    {
    RUBY_DEBUG_BLOCK( "CSRSAlgorithmManager::UnloadGrammarL(si compiled)" );

    iRecognitionAlgMgr->UnloadGrammarL( aGrammar );
    }


// -----------------------------------------------------------------------------
// CSRSAlgorithmManager::ActivateGrammarL
// Unload the specified grammar from the recognizer.
// -----------------------------------------------------------------------------
//
void CSRSAlgorithmManager::ActivateGrammarL( const TSIGrammarID aGrammarID )
    {
    RUBY_DEBUG_BLOCK( "CSRSAlgorithmManager::ActivateGrammarL()" );

    iRecognitionAlgMgr->ActivateGrammarL( aGrammarID );
    }


// -----------------------------------------------------------------------------
// CSRSAlgorithmManager::DeactivateGrammarL
// Unload the specified grammar from the recognizer.
// -----------------------------------------------------------------------------
//
void CSRSAlgorithmManager::DeactivateGrammarL( const TSIGrammarID aGrammarID )
    {
    RUBY_DEBUG_BLOCK( "CSRSAlgorithmManager::DeactivateGrammarL()" );

    iRecognitionAlgMgr->DeactivateGrammarL( aGrammarID );
    }


// -----------------------------------------------------------------------------
// CSRSRecognitionAlgMgr::GetGrammar
// Find grammar based on identifier
// -----------------------------------------------------------------------------
//
void CSRSAlgorithmManager::GetGrammarL( const TSIGrammarID aGrammarID, 
                                        CSICompiledGrammar** aSIActiveGrammar,
                                        CSICompiledGrammar** aSIDeActivatedGrammar )
    {
    RUBY_DEBUG_BLOCK( "CSRSAlgorithmManager::GetGrammarL()" );

    iRecognitionAlgMgr->GetGrammarL( aGrammarID, 
                                     aSIActiveGrammar,
                                     aSIDeActivatedGrammar );
    }


// -----------------------------------------------------------------------------
// CSRSAlgorithmManager::UnloadRule
// Request to unload rule.
// -----------------------------------------------------------------------------
//
void CSRSAlgorithmManager::UnloadRule( TSIGrammarID aGrammarID,
                                       TSIRuleID aRuleID )
    {
    RUBY_DEBUG0( "CSRSAlgorithmManager::UnloadRule()" );

    iRecognitionAlgMgr->UnloadRule( aGrammarID, aRuleID );
    }


// -----------------------------------------------------------------------------
// CSRSAlgorithmManager::LoadEngineParametersL
// Load the specified recognizer parameter(s).
// -----------------------------------------------------------------------------
//
void CSRSAlgorithmManager::LoadEnginePropertiesL( const RArray<TInt>& aParameterId,
                                                  const RArray<TInt>& aParameterValue )
    {
    RUBY_DEBUG_BLOCK( "CSRSAlgorithmManager::LoadEnginePropertiesL()" );

    // Check that parameter ids are valid, settable values
    for ( TInt i = 0; i < aParameterId.Count(); i++ )
        {
        if ( ( aParameterId[i] != KDevASRSendFeatures ) && 
             ( aParameterId[i] != KDevASRAdaptation ) )
            {
            User::Leave( KErrNotSupported );
            }
        }
    iRecognitionAlgMgr->LoadEnginePropertiesL( aParameterId, aParameterValue );
    iVMAlgorithmManager->LoadEnginePropertiesL( aParameterId, aParameterValue );
    }


// -----------------------------------------------------------------------------
// CSRSAlgorithmManager::LoadLexiconL
// Load the specified lexicion into the recognizer.
// -----------------------------------------------------------------------------
//
void CSRSAlgorithmManager::LoadLexiconL( const CSILexicon& aLexicon )
    {
    RUBY_DEBUG_BLOCK( "CSRSAlgorithmManager::LoadLexiconL()" );

    iSILexicon = &aLexicon;

    iRecognitionAlgMgr->LoadLexiconL( aLexicon );
    }


// -----------------------------------------------------------------------------
// CSRSAlgorithmManager::LoadModelsL
// Load the specified models into the recognizer.
// -----------------------------------------------------------------------------
//
void CSRSAlgorithmManager::LoadModelsL( const CSIModelBank& aModels )
    {
    RUBY_DEBUG_BLOCK( "CSRSAlgorithmManager::LoadModelsL()" );

    iSIModelBank = &aModels;

    iRecognitionAlgMgr->LoadModelsL( aModels );
    }


// -----------------------------------------------------------------------------
// CSRSAlgorithmManager::UtteranceData
// Get the recorded audio data accumulated during training.
// -----------------------------------------------------------------------------
//
void CSRSAlgorithmManager::GetUtteranceData( TDes8* /*aBuffer*/, 
                                             TTimeIntervalMicroSeconds32& /*aDuration*/ )
    {
    RUBY_DEBUG0( "CSRSAlgorithmManager::GetUtteranceData()" );
    // Not supported
    }


// -----------------------------------------------------------------------------
// CSRSAlgorithmManager::HandlePlay
// Asynchronously handles the play request.
// -----------------------------------------------------------------------------
//
void CSRSAlgorithmManager::HandlePlayL()
    {
    RUBY_DEBUG0( "CSRSAlgorithmManager::HandlePlayL()" );
    }


// -----------------------------------------------------------------------------
// CSRSAlgorithmManager::StartRecognition
// Request to begin recording.
// -----------------------------------------------------------------------------
//
void CSRSAlgorithmManager::StartRecognition( TTimeIntervalMicroSeconds32 aRecordDuration )
    {
    RUBY_DEBUG0( "CSRSAlgorithmManager::StartRecognition()" );

    iEndFlag = EFalse;
    iRecordDuration = aRecordDuration;
    iRequestFunction = KRecord;
    Ready( KErrNone );
    }

// -----------------------------------------------------------------------------
// CSRSAlgorithmManager::PreStartSamplingL
// Pre-starts sampling
// -----------------------------------------------------------------------------
//
void CSRSAlgorithmManager::PreStartSamplingL()
    {
    RUBY_DEBUG_BLOCK( "" );
#ifdef __FULLDUPLEX_CHANGE
    InitializeDevSoundL();
    StartDevSoundL();
    iPreSamplingStarted = ETrue;
#endif // __FULLDUPLEX_CHANGE
    }

// -----------------------------------------------------------------------------
// CSRSAlgorithmManager::StopRecognition
// Request to stop recording.
// -----------------------------------------------------------------------------
//
void CSRSAlgorithmManager::StopRecognition()
    {
    RUBY_DEBUG0( "CSRSAlgorithmManager::StopRecognition()" );

    iEndFlag = ETrue;
    }


// -----------------------------------------------------------------------------
// CSRSAlgorithmManager::HandleRecord
// Asynchronously handles the recording request.
// -----------------------------------------------------------------------------
//
void CSRSAlgorithmManager::HandleRecordL()
    {
    RUBY_DEBUG_BLOCK( "CSRSAlgorithmManager::HandleRecordL()" );

    if ( StateTransition( EDASRSampling ) ) // Attempt to change state
        {
        // Allocate a buffer big enough for recording.

        if ( iRecordDuration.Int() == 0 )
            {
            iOverallLength = 0;
            }
        else
            {
            TInt bytesPerSecond = ( TInt ) ( iResourceHandler->iSamplingRate * ( iResourceHandler->iBitsPerSample / 8 ) );
            iOverallLength = ( TInt) ( iRecordDuration.Int() * 0.000001 * bytesPerSecond );
            }

        iOverallSampled = 0;

        TInt err = KErrNone;


        // Start the devSound only if client does not provide utterance data.
        if ( iMode == ESiRecognition )
            {
#ifdef __FULLDUPLEX_CHANGE
            if ( !iPreSamplingStarted )
                {
                TRAP( err, StartDevSoundL() );
                }
#else            
            iDevSound->SetPrioritySettings( iPrioritySettings );
            TRAP( err, iDevSound->RecordInitL() );
#endif // __FULLDUPLEX_CHANGE

            // Mark that recognition should be started when first buffer arrives
            iStartRecognition = ETrue;
            }
        else
            {
            TRAPD ( error, iRecognitionAlgMgr->StartRecognitionL() );
            if ( error != KErrNone )
                {
                iRecognitionAlgMgr->Cancel();
                StateTransition( EDASRIdle );
                iDevASRObserver->DevASREvent( EDevASRRecord, error );
                }
            }

        if ( err == KErrNone )
            {
            iDevSoundState = ESoundDeviceRecord;
            iDevASRObserver->DevASREvent( EDevASRRecordStarted, KErrNone );
            
            // Empty audio buffer queue if there happens to be some garbage 
            // from previous recognition.
            while ( !iAudioBufferQue->IsEmpty() )
                {
                iQueItem = iAudioBufferQue->First();
                iAudioBufferQue->Remove( *iQueItem );
                delete iQueItem;
                iQueItem = NULL;
                }
            delete iBufferUnderConstruction;
            iBufferUnderConstruction = NULL;
            iConstructionPoint = 0;
            iPendingRequestSpeechData = EFalse;
            }
        else
            {
            RUBY_DEBUG1( "RecordInitL() Error: %d", err );
            iRecognitionAlgMgr->Cancel();
            StateTransition( EDASRIdle );
            iDevASRObserver->DevASREvent( EDevASRRecord, err );
            }
        }
    else // Wrong state to handle this request
        {
        iDevASRObserver->DevASREvent( EDevASRRecord, KErrAsrInvalidState );
        
        RUBY_DEBUG1( "HandleRecord in wrong state: %d", iDevASRState );
        }

    }


// -----------------------------------------------------------------------------
// CSRSAlgorithmManager::StartRecSession
// Signal the start of a recognition sesion.
// -----------------------------------------------------------------------------
//
TInt CSRSAlgorithmManager::StartRecSession( TRecognizerMode aMode )
    {
    RUBY_DEBUG0( "CSRSAlgorithmManager::StartRecSession()" );

    TInt err( KErrNone );

#ifdef __FULLDUPLEX_CHANGE
    if ( !iPreSamplingStarted )
        {
        TRAP( err, InitializeDevSoundL() );
        }
#else
    TRAP( err, InitializeDevSoundL() );
#endif // __FULLDUPLEX_CHANGE

    if ( err == KErrNone )
        {
        iMode = aMode;

        err = iRecognitionAlgMgr->StartRecSession( aMode );
        if ( err == KErrNone )
            {
            StateTransition( EDASRPreRecognition );
            }
        }

    return err;
    }


// -----------------------------------------------------------------------------
// CSRSAlgorithmManager::EndRecSession
// Signal the end of a recognition sesion.
// -----------------------------------------------------------------------------
//
void CSRSAlgorithmManager::EndRecSession()
    {
    RUBY_DEBUG0( "CSRSAlgorithmManager::EndRecSession()" );

    iRecognitionAlgMgr->EndRecSession();
    StateTransition( EDASRIdle );
    if ( iDevASRState == EDASRIdle )
        {
	    iSIModelBank = NULL;
		iSILexicon = NULL;
        }
    
    delete iDevSound;
    iDevSound = NULL;
    }


// -----------------------------------------------------------------------------
// CSRSAlgorithmManager::SendSpeechData
// Gives data buffer to recognizer.
// -----------------------------------------------------------------------------
//
void CSRSAlgorithmManager::SendSpeechData( TPtrC8& aBuffer, TBool aEnd )
    {
    if ( iMode == ESiRecognitionSpeechInput )
        {
        iRecognitionAlgMgr->SendSpeechData( aBuffer, aEnd );
        }
    }


// -----------------------------------------------------------------------------
// CSRSAlgorithmManager::Cancel
// Cancels the current and any on going requests/tasks.
// -----------------------------------------------------------------------------
//
void CSRSAlgorithmManager::Cancel()
    {
    RUBY_DEBUG0( "CSRSAlgorithmManager::Cancel()" );

    iVMAlgorithmManager->Cancel();

    iRecognitionAlgMgr->Cancel();

    if( iDevASRState != EDASRIdle )
    	{
        //StateTransition( EDASRPreRecognition );
        // Force to pre recognition state
        iDevASRState = EDASRPreRecognition;
    	}

    if ( iDevSoundState != ESoundDeviceNotInitialized )
    	{
        RUBY_DEBUG0( "CSRSAlgorithmManager::Cancel(), Stopping DevSound..." );

        if ( iMode == ESiRecognition )
            {
            if ( iDevSound )
                {
                iDevSound->Stop();
                }
            }
		iDevSoundState = ESoundDeviceStopped;
    	}

    CActive::Cancel();
    }


// -----------------------------------------------------------------------------
// CRecognitionAlgMgr::DoCancel
// Cancels the current and any on going CActive requests/tasks.
// -----------------------------------------------------------------------------
//
void CSRSAlgorithmManager::DoCancel()
    {
    RUBY_DEBUG0( "CSRSAlgorithmManager::DoCancel()" );
    }


// -----------------------------------------------------------------------------
// CSRSAlgorithmManager::EmptyBuffer
// Copies the contents of the received buffer to the holding buffer. Subsequent
// call to EmptyBuffer will append to existing buffer.
// -----------------------------------------------------------------------------
//
TInt CSRSAlgorithmManager::EmptyBuffer( CMMFDataBuffer& aBuffer,
                                        TInt aBufferLength )
    {
    RUBY_DEBUG1( "CSRSAlgorithmManager::EmptyBuffer(): Len=%d bytes", aBufferLength );

    TInt i = 0;
    TInt status = KErrNone;
    TBool iBufferCreated = EFalse;
#ifdef __WINS__
    TInt KNumberOfBuffers = iResourceHandler->iBuffersInWins;
#else
    TInt KNumberOfBuffers = iResourceHandler->iBuffersInThumb;
#endif

    TDes8& ReceivedData = aBuffer.Data();
    TInt iSize = ReceivedData.Length();

#ifdef __FULLDUPLEX_CHANGE
    // If state is not EDASRSampling, then end immediately
    // Samples will be negelected until real recognition starts
    if ( iDevASRState != EDASRRecognitionSampling )
        {
        iDevSound->RecordData();
        return status;
        }
    else
        {
        // Reset pre-sampling flag
        iPreSamplingStarted = EFalse; 
        }
#endif // __FULLDUPLEX_CHANGE

    // If DevSound has not filled the whole buffer, something 
    // is wrong in the sampling
    if( aBufferLength < ReceivedData.MaxLength() )
        {
        status = KErrEof;
        }

    // iOverallLength checks how much is sampled during all the callbacks
    if ( iOverallLength != 0 )
        {
        if ( iOverallSampled >= iOverallLength )
            {
            status = KErrOverflow;
            }
        }

    TInt silentFrames = iResourceHandler->iSilenceFrames;

    // Create new buffer if previous one has been queued
    if ( iBufferUnderConstruction == NULL )
        {
        iBufferUnderConstruction = new TUint8[ iSize * KNumberOfBuffers ];
        if ( !iBufferUnderConstruction )
            {
            return KErrNoMemory;
            }
        iConstructionPoint = 0;
        }

    // Copy data, put silence into the beginning of buffer if needed
    for ( i = 0; i < iSize; i++ )
        {
        if ( ( iOverallSampled + i ) < silentFrames )
            {
            // Do not copy zeros
            //iBufferUnderConstruction[ iConstructionPoint ] = 0;
            }
        else
            {
            iBufferUnderConstruction[ iConstructionPoint ] = ReceivedData[ i ];
            iConstructionPoint++;
            }
        }

    // Count the number of sampled bytes
    iOverallSampled = iOverallSampled + iSize;

    // If internal buffer overflowed or EOF, mark this the final block of data
    // Mark as the final block also if EndRecord() has been explicitly called
    if ( ( status == KErrOverflow ) || ( status == KErrEof ) || iEndFlag )
        {
        CQueItem* qItem( NULL );
        TRAPD( err, qItem = CQueItem::NewL( &iBufferUnderConstruction[0], iConstructionPoint ) );
        if ( err != KErrNone )
            {
            return err;
            }
        qItem->iFinalBlock = ETrue;
        iEndFlag = EFalse;
        iAudioBufferQue->AddLast( *qItem );
        iBufferUnderConstruction = NULL;
        iConstructionPoint = 0;
        iBufferCreated = ETrue;

        RUBY_DEBUG0( "CSRSAlgorithmManager::EmptyBuffer(): Sampling ended due to timeout!!" );
        }
    else
        {
        // Notify devsound
        iDevSound->RecordData();

        // If next buffer does not fit to the buffer under construction
        // put it to queue and start new when next callback arrives
        if ( iConstructionPoint + iSize > iSize * KNumberOfBuffers )
            {
            // Put data to queue
            CQueItem* qItem( NULL );
            TRAPD( err, qItem = CQueItem::NewL( &iBufferUnderConstruction[0], iConstructionPoint ) );
            if ( err != KErrNone )
                {
                return err;
                }
            qItem->iFinalBlock = EFalse;
            iAudioBufferQue->AddLast( *qItem );
            iBufferCreated = ETrue;
            }
        }

    if ( iBufferCreated )
        {

#ifdef AUDIOBUFFER_TO_FILE
        TInt connectError = iFs.Connect();
        if ( connectError != KErrNone )
            {
            return connectError;
            }
        _LIT( KBufferFileName, "C:\\documents\\devasraudiobuffer.raw" );
        if ( !iFileCreated )
            {
            iBufferDataFile.Replace( iFs, KBufferFileName, EFileWrite );
            iFileCreated = ETrue;
            }
        else
            {
            TInt openError = iBufferDataFile.Open( iFs, KBufferFileName, EFileWrite );
            if ( openError != KErrNone )
                {
                return openError;
                }
            }
        
        TPtr8 ptr( &iBufferUnderConstruction[0], iConstructionPoint, iConstructionPoint );
        TInt pos = 0;
        iBufferDataFile.Seek( ESeekEnd, pos );
        iBufferDataFile.Write( pos, ptr );
        iBufferDataFile.Close();
        iFs.Close();
#endif

        iBufferUnderConstruction = NULL;
        iConstructionPoint = 0;
        
        // Start recognition if it has not been already started
        if ( iStartRecognition )
            {
            TRAP( status, iRecognitionAlgMgr->StartRecognitionL() );
            iStartRecognition = EFalse;
            }
        
        // If RequestSpeechData() gets called when there is no data in queue, we
        // should call it again to deliver the new data to recognizer
        if ( iPendingRequestSpeechData )
            {
            iPendingRequestSpeechData = EFalse;
            RequestSpeechData();
            }
        }
    
    return status;
    }
    
    
// -----------------------------------------------------------------------------
// CSRSAlgorithmManager::FillBuffer
// Copies a portion of the holding buffer to the received buffer.
// -----------------------------------------------------------------------------
//
TInt CSRSAlgorithmManager::FillBuffer( CMMFDataBuffer& /*aBuffer*/, 
                                       TInt /*aBufferLength*/ )
    {
    RUBY_DEBUG0( "CSRSAlgorithmManager::FillBuffer()" );

    return KErrNotSupported;
    }


// -----------------------------------------------------------------------------
// CSRSAlgorithmManager::SetPrioritySettings
// Store the priority setting for the sound device.
// -----------------------------------------------------------------------------
//
void CSRSAlgorithmManager::SetPrioritySettings( const TMMFPrioritySettings& aPrioritySettings )
    {
    iPrioritySettings = aPrioritySettings;
    // Always use preference meant for recognition
    iPrioritySettings.iPref = ( TMdaPriorityPreference ) KAudioPrefVocosRecog;
    }


// -----------------------------------------------------------------------------
// CSRSAlgorithmManager::InitializeDevSoundL
// 
// -----------------------------------------------------------------------------
//
void CSRSAlgorithmManager::InitializeDevSoundL()
    {
    if ( !iDevSound )
        {
        // Instance
        iDevSound = CMMFDevSound::NewL();
        }
    
    // Initialization        
    iDevSound->InitializeL( *this, EMMFStateRecording );
    
    // Wait for initialization callback
    if ( !iAudioWait.IsStarted() )
        {
        iAudioWait.Start();
        }    

    // Configuration
    ConfigureSoundDeviceL();
    }
        
        
// -----------------------------------------------------------------------------
// CSRSAlgorithmManager::StartDevSoundL
// 
// -----------------------------------------------------------------------------
//
void CSRSAlgorithmManager::StartDevSoundL()
    {
    RUBY_DEBUG_BLOCK( "" );
    iDevSound->SetPrioritySettings( iPrioritySettings );
    iDevSound->RecordInitL();
    iDevSoundState = ESoundDeviceRecord;
    }


// -----------------------------------------------------------------------------
// CSRSAlgorithmManager::StateTransition
// Change to the specified state if possible. If state change is invalid,
// EFalse is returned, otherwise, ETrue.
// -----------------------------------------------------------------------------
//
TBool CSRSAlgorithmManager::StateTransition( TDevASRState aTargetState )
    {

    TBool result = ETrue;

#ifdef _DEBUG
    DevASRState();
#endif

    switch ( aTargetState )
        {
        case EDASRIdle:
            iDevASRState = aTargetState;
            break;

        case EDASRInitTrain:
            if ( iDevASRState == EDASRIdle )
                {
                iDevASRState = aTargetState;
                }
            else
                {
                result = EFalse;
                }
            break;

        case EDASRTrain:
            if ( ( iDevASRState == EDASRTrain ) ||
                ( iDevASRState == EDASRInitTrain ) ||
                ( iDevASRState == EDASRTrainSampling ) )
                {
                iDevASRState = aTargetState;
                }
            else
                {
                result = EFalse;
                }
            break;

        case EDASRSampling:
            if ( iDevASRState == EDASRTrain )
                {
                iDevASRState = EDASRTrainSampling;
                }
            else if ( iDevASRState == EDASRRecognition )
                {
                iDevASRState = EDASRRecognitionSampling;
                }
            else
                {
                result = EFalse;
                }
            break;

        case EDASRPlayback:
            if ( iDevASRState == EDASRIdle )
                {
                iDevASRState = EDASRPlayback;
                }
            else if ( iDevASRState == EDASRPreRecognition )
                {
                iDevASRState = EDASRRecognitionPlayback;
                }
            else
                {
                result = EFalse;
                }
            break;

        case EDASRPreRecognition:
            if ( ( iDevASRState == EDASRIdle ) ||
                ( iDevASRState == EDASRRecognition ) ||
                ( iDevASRState == EDASRRecognitionPlayback ) )
                {
                iDevASRState = aTargetState;
                }
            else
                {
                result = EFalse;
                }
            break;

        case EDASRRecognitionPlayback:
            if (iDevASRState == EDASRPreRecognition)
                {
                iDevASRState = aTargetState;
                }
            else
                {
                result=EFalse;
                }
            break;

        case EDASRInitRecognition:
            if ((iDevASRState == EDASRInitRecognition) ||
                (iDevASRState == EDASRPreRecognition))
                {
                iDevASRState = aTargetState;
                }
            else
                {
                result=EFalse;
                }
            break;

        case EDASRRecognition:
            if ( ( iDevASRState == EDASRInitRecognition ) ||
                ( iDevASRState == EDASRRecognitionSampling ) )
                {
                iDevASRState = aTargetState;
                }
            else
                {
                result = EFalse;
                }
            break;

        case EDASRCancel:
            break;

        default:
            RUBY_DEBUG1( "Invalid state: %d", aTargetState );
            break;
        };

#ifdef _DEBUG
    DevASRState();
    iRecognitionAlgMgr->AlgorithmState();
#endif
    return result;
    }


// -----------------------------------------------------------------------------
// CSRSAlgorithmManager::TranslateError
// Translate internal errors to system errors
// -----------------------------------------------------------------------------
//
TInt CSRSAlgorithmManager::TranslateError( TInt aError )
    {
    RUBY_DEBUG1( "CSRSAlgorithmManager::TranslateError(%d)", aError );

    TInt error = aError;

     switch ( aError )
        {
        case KErrTooEarly:
            error = KErrAsrSpeechTooEarly;
            break;
        case KErrNoSpeech:
            error = KErrAsrNoSpeech;
            break;
        case KErrTooLong:
            error = KErrAsrSpeechTooLong;
            break;
        case KErrTooShort:
            error = KErrAsrSpeechTooShort;
            break;
        default:
            RUBY_DEBUG1( "Unmapped Error: %d", aError );
            break;
        };

    return error;
    }


// -----------------------------------------------------------------------------
// DevSound Observer MIXIN implementation begins
// -----------------------------------------------------------------------------

// -----------------------------------------------------------------------------
// CSRSAlgorithmManager::InitializeComplete
// Initialization of DevSound is complete.
// -----------------------------------------------------------------------------
//
void CSRSAlgorithmManager::InitializeComplete( TInt aError )
    {
    RUBY_DEBUG1( "InitializeComplete[%d]", aError );

    if ( aError == KErrNone  )
        {
		iDevSoundState = ESoundDeviceInitialized;
		}
		
    // Free wait loop
    if ( iAudioWait.IsStarted() )
        {
        iAudioWait.AsyncStop();
        }                       
    }

// -----------------------------------------------------------------------------
// CSRSAlgorithmManager::ToneFinished
// Finished playing tones
// -----------------------------------------------------------------------------
//
void CSRSAlgorithmManager::ToneFinished( TInt /*aError*/ )
    {
    // Should never be called because no tone services is required.
    }


// -----------------------------------------------------------------------------
// CSRSAlgorithmManager::BufferToBeFilled
// Buffer from DevSound to be filled with audio data.
// -----------------------------------------------------------------------------
//
void CSRSAlgorithmManager::BufferToBeFilled( CMMFBuffer* aBuffer )
    {
    CMMFDataBuffer* buffer = STATIC_CAST( CMMFDataBuffer*, aBuffer );

    if ( FillBuffer( *buffer, aBuffer->RequestSize() ) == KErrNone )
        {
        iDevSound->PlayData();
        }
    }

// -----------------------------------------------------------------------------
// CSRSAlgorithmManager::PlayError
// Playing of an audio sample has completed successfully or otherwise.
// -----------------------------------------------------------------------------
//
void CSRSAlgorithmManager::PlayError( TInt aError )
    {
    RUBY_DEBUG1( "CSRSAlgorithmManager::PlayError[%d]", aError );

    if ( iDevASRState != EDASRIdle )
		{

		if ( iDevASRState == EDASRRecognitionPlayback )
			{
			StateTransition( EDASRPreRecognition );
			}
		else
			{
			StateTransition( EDASRIdle );
			}

		if ( aError == KErrUnderflow )
			{
			iDevASRObserver->DevASREvent( EDevASRPlay, KErrNone );
			}
		else
			{
			iDevASRObserver->DevASREvent( EDevASRPlay, aError );
			}

		}

    }

// -----------------------------------------------------------------------------
// CSRSAlgorithmManager::BufferToBeEmptied
// An audio buffer is ready to be emptied.
// -----------------------------------------------------------------------------
//
void CSRSAlgorithmManager::BufferToBeEmptied( CMMFBuffer* aBuffer )
    {
    RUBY_DEBUG0( "" );    
    if ( iDevASRState == EDASRIdle && !iPreSamplingStarted )
        {
        RUBY_DEBUG0( "stopping devsound" );
        iDevSound->Stop();
		iDevSoundState = ESoundDeviceStopped;
        return;
        }

    RUBY_DEBUG0( "processing callback" );
    CMMFDataBuffer* buffer = STATIC_CAST( CMMFDataBuffer*, aBuffer );
	EmptyBuffer( *buffer, aBuffer->RequestSize() );
    }


// -----------------------------------------------------------------------------
// CSRSAlgorithmManager::RecordError
// Recording has completed successfully or otherwise.
// -----------------------------------------------------------------------------
//
void CSRSAlgorithmManager::RecordError( TInt aError )
    {
    RUBY_DEBUG1( "CSRSAlgorithmManager::RecordError[%d]", aError );

    iPreSamplingStarted = EFalse;
    iRecognitionAlgMgr->Cancel();
    StateTransition( EDASRIdle );
    iDevASRObserver->DevASREvent( EDevASRRecord, aError );
    }


// -----------------------------------------------------------------------------
// CSRSAlgorithmManager::ConvertError
// Conversion has completed successfully or otherwise.
// -----------------------------------------------------------------------------
//
void CSRSAlgorithmManager::ConvertError( TInt /*aError*/ )
    {
    // This method should never be called.
    }


// -----------------------------------------------------------------------------
// CSRSAlgorithmManager::RecordError
// Callback for custom commands
// -----------------------------------------------------------------------------
//
void CSRSAlgorithmManager::DeviceMessage( TUid /*aMessageType*/, 
                                          const TDesC8& /*aMsg*/ )
    {
    RUBY_DEBUG0( "CSRSAlgorithmManager::DeviceMessage" );
    }

// -----------------------------------------------------------------------------
// CSRSAlgorithmManager::SendEventToClient
// Receives and event from DevSound send it to the appropriate handler.
// -----------------------------------------------------------------------------
//
void CSRSAlgorithmManager::SendEventToClient( const TMMFEvent& aEvent )
    {
    RUBY_DEBUG0( "CSRSAlgorithmManager::SendEventToClient()" );

	if ( aEvent.iErrorCode != KErrNone )
		{
		if ( iDevSoundState == ESoundDeviceRecord )
			{
			RecordError( aEvent.iErrorCode );
			}
		else if ( iDevSoundState == ESoundDevicePlayback )
			{
			PlayError( aEvent.iErrorCode );
			}
		}

    }


// -----------------------------------------------------------------------------
// DevSound Observer MIXIN impl ends
// -----------------------------------------------------------------------------


// -----------------------------------------------------------------------------
// RecognitionAlgMgr Observer MIXIN implementation begins
// -----------------------------------------------------------------------------

// -----------------------------------------------------------------------------
// CSRSAlgorithmManager::AdaptComplete
// Model adaptation has finished.
// -----------------------------------------------------------------------------
//
void CSRSAlgorithmManager::AdaptComplete( TInt aResultCode )
    {
    RUBY_DEBUG1( "CSRSAlgorithmManager::AdaptComplete(%d)", aResultCode );

    iDevASRObserver->DevASREvent( EDevASRAdapt, aResultCode );
    }


// -----------------------------------------------------------------------------
// CSRSAlgorithmManager::InitFEComplete
// Initialization of frontend algorithm has completed.
// -----------------------------------------------------------------------------
//
void CSRSAlgorithmManager::InitFEComplete( TInt aResultCode )
    {
    RUBY_DEBUG1( "CSRSAlgorithmManager::InitFEComplete(%d)", aResultCode );

    // Ignore events if we're idle.
    if ( ( iDevASRState == EDASRInitTrain ) || ( iDevASRState == EDASRInitRecognition ) )
        {
        if ( aResultCode == KErrNone )
            {
            if ( iDevASRState == EDASRInitTrain )
                {
                iDevASRState = EDASRTrain;
                }
            else if ( iDevASRState == EDASRInitRecognition )
                {
                iDevASRState = EDASRRecognition;
                }
            iDevASRObserver->DevASREvent( EDevASRInitFrontend, aResultCode );
            }
        else
            {
            StateTransition( EDASRIdle );
            iDevASRObserver->DevASREvent( EDevASRInitFrontend, TranslateError( aResultCode ) );
            }
        }
    }

// -----------------------------------------------------------------------------
// CSRSAlgorithmManager::InitRecognizerBEComplete
// Initialization of backend algorithm for recognition has completed.
// -----------------------------------------------------------------------------
//
void CSRSAlgorithmManager::InitRecognizerBEComplete( TInt aResultCode )
    {
    RUBY_DEBUG1( "CSRSAlgorithmManager::InitRecognizerBEComplete(%d)", aResultCode );

    if ( StateTransition( EDASRInitRecognition ) )
        {
        if ( aResultCode == KErrNone )
            {
            iDevASRObserver->DevASREvent( EDevASRInitRecognitionBackend, aResultCode );
            }
        else
            {
            StateTransition( EDASRIdle );
            iDevASRObserver->DevASREvent( EDevASRInitRecognitionBackend, TranslateError( aResultCode ) );
            }
        }

    }

// -----------------------------------------------------------------------------
// CSRSAlgorithmManager::LoadGrammarComplete
// Loading of grammar into recognizer has completed.
// -----------------------------------------------------------------------------
//
void CSRSAlgorithmManager::LoadGrammarComplete( TInt aResultCode )
    {
    RUBY_DEBUG1( "CSRSAlgorithmManager::LoadGrammarComplete(%d)", aResultCode );

	TDevASREvent event = EDevASRLoadGrammar;
    
    if ( aResultCode == KErrNone )
        {
        iDevASRObserver->DevASREvent( event, aResultCode );
        }
    else
        {
        //StateTransition( EDASRIdle );
        iDevASRObserver->DevASREvent( event, TranslateError( aResultCode ) );
        }
    }


// -----------------------------------------------------------------------------
// CSRSAlgorithmManager::UnloadGrammarComplete
// Grammar has beed unloaded.
// -----------------------------------------------------------------------------
//
void CSRSAlgorithmManager::UnloadGrammarComplete( TInt aResultCode )
    {
    RUBY_DEBUG1( "CSRSAlgorithmManager::UnloadGrammarComplete(%d)", aResultCode );

	TDevASREvent event = EDevASRUnloadGrammar;
    
    if ( aResultCode == KErrNone )
        {
        iDevASRObserver->DevASREvent( event, aResultCode );
        }
    else
        {
        iDevASRObserver->DevASREvent( event, TranslateError( aResultCode ) );
        }
    }


// -----------------------------------------------------------------------------
// CSRSAlgorithmManager::ActivateGrammarComplete
// Grammar activation has been completed.
// -----------------------------------------------------------------------------
//
void CSRSAlgorithmManager::ActivateGrammarComplete( TInt aResultCode )
    {
    RUBY_DEBUG1( "CSRSAlgorithmManager::ActivateGrammarComplete(%d)", aResultCode );

    if ( iDevASRState == EDASRPreRecognition )
        {
        iDevASRObserver->DevASREvent( EDevASRActivateGrammar, aResultCode );
        }  
    }


// -----------------------------------------------------------------------------
// CSRSAlgorithmManager::DeActivateGrammarComplete
// Grammar deactivation has been completed.
// -----------------------------------------------------------------------------
//
void CSRSAlgorithmManager::DeActivateGrammarComplete( TInt aResultCode )
    {
    RUBY_DEBUG1( "CSRSAlgorithmManager::DeActivateGrammarComplete(%d)", aResultCode );

    if ( iDevASRState == EDASRPreRecognition )
        {
        iDevASRObserver->DevASREvent( EDevASRDeactivateGrammar, aResultCode );
        }
    }


// -----------------------------------------------------------------------------
// CSRSAlgorithmManager::LoadLexiconComplete
// Loading of lexicon into recognizer has completed.
// -----------------------------------------------------------------------------
//
void CSRSAlgorithmManager::LoadLexiconComplete( TInt aResultCode )
    {
    RUBY_DEBUG1( "CSRSAlgorithmManager::LoadLexiconComplete(%d)", aResultCode );
    
    if ( aResultCode == KErrNone )
        {
        iDevASRObserver->DevASREvent( EDevASRLoadLexicon, aResultCode );
        }
    else
        {
        //StateTransition( EDASRIdle );
        iDevASRObserver->DevASREvent( EDevASRLoadLexicon, TranslateError( aResultCode ) );
        }
    }


// -----------------------------------------------------------------------------
// CSRSAlgorithmManager::LoadModelsComplete
// Loading of models into recognizer has completed.
// -----------------------------------------------------------------------------
//
void CSRSAlgorithmManager::LoadModelsComplete( TInt aResultCode )
    {
    RUBY_DEBUG1( "CSRSAlgorithmManager::LoadModelsComplete(%d)", aResultCode );
    
    if ( aResultCode == KErrNone )
        {
        iDevASRObserver->DevASREvent( EDevASRLoadModels, aResultCode );
        }
    else
        {
        //StateTransition( EDASRIdle );
        iDevASRObserver->DevASREvent( EDevASRLoadModels, TranslateError( aResultCode ) );
        }
    }


// -----------------------------------------------------------------------------
// CSRSAlgorithmManager::RequestSpeechData
// Speech data is needed.
// -----------------------------------------------------------------------------
//
void CSRSAlgorithmManager::RequestSpeechData()
    {
    RUBY_DEBUG0( "CSRSAlgorithmManager::RequestSpeechData()" );

    if ( iMode == ESiRecognitionSpeechInput )
        {
        iDevASRObserver->RequestSpeechData();
        }
    else
        {
        // The processed sample descriptor can be deleted
        delete iQueItem; 
        iQueItem = NULL;
        
        if ( ( iDevASRState == EDASRTrainSampling ) || ( iDevASRState == EDASRRecognitionSampling ) )
            {
            // Check if there's more data to send and if so, send the next block of data
            if ( iAudioBufferQue->IsEmpty() )
                {
                iPendingRequestSpeechData = ETrue;
                iProcessingUtterance = EFalse;
                }
            else
                {
                iQueItem = iAudioBufferQue->First();
                iRecognitionAlgMgr->SendSpeechData( iQueItem->iDataBlock, iQueItem->iFinalBlock );
                iAudioBufferQue->Remove( *iQueItem );
                }        
            }
        }
    }


// -----------------------------------------------------------------------------
// CSRSAlgorithmManager::FeatureVectorDataRcvd
// Feature vector data received from frontend.
// -----------------------------------------------------------------------------
//
void CSRSAlgorithmManager::FeatureVectorDataRcvd( const TDesC8& aFV,
                                                  TInt32 aSNR,
                                                  TInt32 aPosition )
    {
    iDevASRObserver->FeatureVectorDataRcvd( aFV, aSNR, aPosition );
    }


// -----------------------------------------------------------------------------
// CSRSAlgorithmManager::EouDetected
// Frontend finished extracting feature vectors from PCM data.
// -----------------------------------------------------------------------------
//
void CSRSAlgorithmManager::EouDetected( TInt aResultCode )
    {
    RUBY_DEBUG1( "CSRSAlgorithmManager::EouDetected(%d)", aResultCode );

    if ( iDevASRState == EDASRTrainSampling )
        {
        
        if ( aResultCode != KErrNone )
            {
            RUBY_DEBUG1( "CSRSAlgorithmManager::EouDetected(): Training ERROR %d", aResultCode );

            StateTransition( EDASRIdle );
            iDevSound->Stop();
            iDevSoundState = ESoundDeviceStopped;
            iDevASRObserver->DevASREvent( EDevASRTrain, TranslateError( aResultCode ) );
            return;
            }
        
        // If we fail to get the utterance duration, there's probably not enough frames to calculate
        // utterance duration. We will fail training with "too short".
        if ( !iRecognitionAlgMgr->GetUtteranceDuration(iStartFrame, iEndFrame, iFrameLength) )
            {
            StateTransition(EDASRIdle);
            iDevSound->Stop();
            iDevSoundState = ESoundDeviceStopped;
            iDevASRObserver->DevASREvent( EDevASRTrain, KErrAsrSpeechTooShort );
            return;
            }
        
        RUBY_DEBUG1( "Start frame: %d", iStartFrame );
        RUBY_DEBUG1( "End frame: %d", iEndFrame );
        RUBY_DEBUG1( "Frame Length: %f", iFrameLength );

        // Now, calculate the start and end point in the audio buffer for encoding
        
        RUBY_DEBUG1( "Padding start frames: %d", iResourceHandler->iPadStartFrames );

        // Pad additional frame to start and end to prevent clipping during utterance playback.
        
        if( (iStartFrame - iResourceHandler->iPadStartFrames) <= 0 )
            {
            iStartFrame = 0;
            }
        else
            {
            iStartFrame = iStartFrame - iResourceHandler->iPadStartFrames;
            }
        
        iBufferStartPoint = (TUint32)(iStartFrame * iFrameLength * iResourceHandler->iSamplingRate * 2);
        
        RUBY_DEBUG1( "Padding start frames: %d", iResourceHandler->iPadEndFrames );

        iBufferEndPoint = (TUint32)((iEndFrame + iResourceHandler->iPadEndFrames) * iFrameLength *
            iResourceHandler->iSamplingRate * 2);
        
        if ( iBufferEndPoint >= iStartPoint - 1 ) // Do not pad beyond recorded point
            {
            iBufferEndPoint = iStartPoint - 1; // Set to the last byte recorded
            }
        
        if ( iBufferEndPoint > iStopPoint ) // Cannot pad more than buffer size allows
            {
            iBufferEndPoint = iStopPoint;
            }
        
        StateTransition(EDASRTrain);
        iDevSound->Stop();
        iDevSoundState = ESoundDeviceStopped;
        }
    
    // It is possible that the frontend has completed processing while the audio
    // buffer is not yet full.
    // The recording can be stopped as the frontend has detected end of utterance.
    
    else if ( iDevASRState == EDASRRecognitionSampling )
        {
        
        if ( ( aResultCode != KErrNone ) && ( aResultCode != KErrTooLong ) )
            {
            RUBY_DEBUG1( "CSRSAlgorithmManager::EouDetected(): Recognition ERROR %d", aResultCode );

            StateTransition( EDASRIdle );
            iRecognitionAlgMgr->Cancel();
            iDevSound->Stop();
            iDevASRObserver->DevASREvent( EDevASRRecognize, TranslateError( aResultCode ) );
            return;
            }
        
        StateTransition( EDASRRecognition );
      
        iDevSound->Stop();
       
        iDevSoundState = ESoundDeviceStopped;
        }
    else // We are in the wrong state to handle this event
        {
        RUBY_DEBUG0( "CSRSAlgorithmManager::EouDetected(): WRONG STATE" );
        return;
        }
    
    iDevASRObserver->DevASREvent( EDevASREouDetected, KErrNone );
    }


// -----------------------------------------------------------------------------
// CSRSAlgorithmManager::TrainComplete
// The training backend has finished processing feature vectors. A Model is
// created.
// -----------------------------------------------------------------------------
//
void CSRSAlgorithmManager::TrainComplete( TInt aResultCode )
    {
    RUBY_DEBUG1( "CSRSAlgorithmManager::TrainComplete(%d)", aResultCode );

    if ( iDevASRState == EDASRTrain )
        {
        // Training is complete, DevASR can return to Idle state.
        StateTransition( EDASRIdle );

        iDevASRObserver->DevASREvent( EDevASRTrain, TranslateError( aResultCode ) );
        }
    }


// -----------------------------------------------------------------------------
// CSRSAlgorithmManager::UnloadRuleComplete
// Rule has been blacklisted successfully or otherwise.
// -----------------------------------------------------------------------------
//
void CSRSAlgorithmManager::UnloadRuleComplete( TInt aResultCode )
    {
    RUBY_DEBUG1( "CSRSAlgorithmManager::UnloadRuleComplete(%d)", aResultCode );
    
    iDevASRObserver->DevASREvent( EDevASRUnloadRule, aResultCode );
    }


// -----------------------------------------------------------------------------
// CSRSAlgorithmManager::RecognitionComplete
// The recognition backend has finished processing feature vectors. A recognition
// result is created.
// -----------------------------------------------------------------------------
//
void CSRSAlgorithmManager::RecognitionComplete( TInt aResultCode )
    {
    RUBY_DEBUG1( "CSRSAlgorithmManager::RecognitionComplete(%d)", aResultCode );

    // Recognition is complete, DevASR can return to pre-recognition state
    if ( StateTransition( EDASRPreRecognition ) )
        {
        // Mark that sampling can be ended if not stopped yet
        iEndFlag = ETrue;
		iDevASRObserver->DevASREvent( EDevASRRecognize, TranslateError( aResultCode ) );
        }
    else
        {
        if ( iDevASRState == EDASRRecognitionSampling )
            {
            StateTransition( EDASRRecognition );
            iDevSound->Stop();
			iDevSoundState = ESoundDeviceStopped;
            iDevASRObserver->DevASREvent( EDevASREouDetected, KErrNone );
            StateTransition( EDASRPreRecognition );
            iDevASRObserver->DevASREvent( EDevASRRecognize, TranslateError( aResultCode ) );
            }
        }
    }


// -----------------------------------------------------------------------------
// RecAlgMgr Observer MIXIN impl ends
// -----------------------------------------------------------------------------

// -----------------------------------------------------------------------------
// MVmAlgMgrObserver MIXIN impl starts
// -----------------------------------------------------------------------------

// -----------------------------------------------------------------------------
// CSRSAlgorithmManager::CombineComplete
// Grammar combination is ready.
// -----------------------------------------------------------------------------
//
void CSRSAlgorithmManager::CombineComplete( HBufC8* aResult, TInt aError )
    {
    // Forward call to reco alg manager
    iRecognitionAlgMgr->CombineComplete( aResult, aError );
    }


// -----------------------------------------------------------------------------
// MVmAlgMgrObserver MIXIN impl ends
// -----------------------------------------------------------------------------


// -----------------------------------------------------------------------------
// Active object implementation begins
// -----------------------------------------------------------------------------


// -----------------------------------------------------------------------------
// CSRSAlgorithmManager::RunL
// Handle the requested function asynchronously.
// result is created.
// -----------------------------------------------------------------------------
//
void CSRSAlgorithmManager::RunL()
    {

    switch ( iRequestFunction )
        {
        case KRecord:
            TRAPD( err, HandleRecordL() );
            if ( err )
                {
                iRecognitionAlgMgr->Cancel();
                StateTransition( EDASRIdle );
                iDevASRObserver->DevASREvent( EDevASRRecord, TranslateError( err ) );
                }
            break;

        case KPlay:

            TRAPD( err1, HandlePlayL() );
            if ( err1 )
                {
                StateTransition( EDASRIdle );
                iDevASRObserver->DevASREvent( EDevASRPlay, TranslateError( err1 ) );
                }
            break;

        default:
            break;
        };
    }


// -----------------------------------------------------------------------------
// CSRSAlgorithmManager::Ready
// Utility function to post a request complete.
// result is created.
// -----------------------------------------------------------------------------
//
void CSRSAlgorithmManager::Ready( const TInt aStatus )
    {
    TRequestStatus* stat = &iStatus;
    User::RequestComplete( stat, aStatus );
    SetActive();
    }


// -----------------------------------------------------------------------------
// Active object impl ends
// -----------------------------------------------------------------------------


// -----------------------------------------------------------------------------
// CSRSAlgorithmManager::DevASRState
// Utility function print out the state of DevASR for unit testing.
// result is created.
// -----------------------------------------------------------------------------
//
void CSRSAlgorithmManager::DevASRState()
    {

#ifdef _DEBUG
    switch ( iDevASRState )
        {
        case EDASRIdle:
            RUBY_DEBUG1( "DevASR is: [%d] - EDASRIdle", iDevASRState );
            break;

        case EDASRInitTrain:
            RUBY_DEBUG1( "DevASR is: [%d] - EDASRInitTrain", iDevASRState );
            break;

        case EDASRTrain:
            RUBY_DEBUG1( "DevASR is: [%d] - EDASRTrain", iDevASRState );
            break;

        case EDASRRecognitionSampling:
            RUBY_DEBUG1( "DevASR is: [%d] - EDASRRecognitionSampling", iDevASRState );
            break;

        case EDASRTrainSampling:
            RUBY_DEBUG1( "DevASR is: [%d] - EDASRTrainSampling", iDevASRState );
            break;

        case EDASRPlayback:
            RUBY_DEBUG1( "DevASR is: [%d] - EDASRPlayback", iDevASRState );
            break;

        case EDASRPreRecognition:
            RUBY_DEBUG1( "DevASR is: [%d] - EDASRPreRecognition", iDevASRState );
            break;

        case EDASRRecognitionPlayback:
            RUBY_DEBUG1( "DevASR is: [%d] - EDASRRecognitionPlayback", iDevASRState );
            break;

        case EDASRInitRecognition:
            RUBY_DEBUG1( "DevASR is: [%d] - EDASRInitRecognition", iDevASRState );
            break;

        case EDASRRecognition:
            RUBY_DEBUG1( "DevASR is: [%d] - EDASRRecognition", iDevASRState );
            break;

        case EDASRCancel:
            RUBY_DEBUG1( "DevASR is: [%d] - EDASRCancel", iDevASRState );
        default:
            RUBY_DEBUG1( "DevASR is: [%d] - Unknown", iDevASRState );
            break;
        };
#endif

    }