srsf/vcommandhandler/src/vcommandservices.cpp
changeset 13 57b735022c18
parent 1 b13cd05eeb2f
--- a/srsf/vcommandhandler/src/vcommandservices.cpp	Mon Jan 18 20:20:30 2010 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,794 +0,0 @@
-/*
-* Copyright (c) 2006-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:  Implementation of VCommand Handler that links the VCommand 
-*                app to VAS
-*
-*/
-
-
-#include "rubydebug.h"
-#include "vcommandservices.h"
-#include "contextprovider.h"
-#include "tagnameset.h"
-#include "taggetter.h"
-#include "tagcommandconverter.h"
-#include "tagplayer.h"
-#include <nssvascoreconstant.h>
-
-#include <s32mem.h>
-#include <nssvascvasdbmgr.h>
-#include "vcommandinternalapi.h"
-
-// For CleanupResetAndDestroy
-#include <mmfcontrollerpluginresolver.h>  
-
-
-/**
-* Name of the global mutex used to serialize the operations
-*/
-_LIT( KCommandHandlerLockName, "VCOMHNDLR" );
-
-_LIT( KCommandHandlerPanic, "VCH" );
-
-TAny* TVCommandTagPtrArrayKey::At( TInt aIndex ) const
-    {
-    MNssTag* tag ( NULL );
-    TInt* key (NULL);
-    if ( aIndex==KIndexPtr )
-        {
-        // iPtr is a pointer to the array element which is a pointer itself 
-        // in case of the CArrayPtr
-        tag = *(MNssTag**)iPtr;
-        key = &tag->RRD()->IntArray()->At( 0 );
-        }
-    else 
-        {
-        // iBase is CBufBase* of the searched array
-        // CBufBase memory buffer stores pointers to MNssTag* (i.e. MNssTag**)
-        // iBase->Ptr returns TPtr8 to the desired pointer 
-        // TPtr8.Ptr returns TUint8* of the element
-        // This element itself is a pointer to CPerson (i.e. MNssTag**)
-        tag = *(MNssTag**)iBase->Ptr( aIndex*sizeof( MNssTag** ) ).Ptr();
-        key = &tag->RRD()->IntArray()->At( 0 );
-        }        
-        return key;        
-    }
-    
-// Construction/destruction
-CVCommandService* CVCommandService::NewL( MVCommandHandlerObserver* aObserver )
-    {
-    CVCommandService* self = new (ELeave) CVCommandService( aObserver );
-    CleanupStack::PushL( self );
-    self->ConstructL();
-    CleanupStack::Pop( self );
-    return self;
-    }
-    
-CVCommandService::~CVCommandService()
-    {
-    RUBY_DEBUG0( "CVCommandService::~CVCommandService" );
-    delete iGlobalTickWatcher;
-    iGlobalTickProperty.Close();
-    delete iVasDbManager;
-    iCommands.ResetAndDestroy();
-    delete iTagPlayer;
-    if( iLock.IsHeld() )
-        {
-        RUBY_DEBUG0( "CVCommandService::~CVCommandService. Mutex is still held.\
-                     Signaling it" );
-        iLock.Signal();
-        }
-    iLock.Close();
-    }
-   
-// From the MVCService
-
-/**
-* Synchronous. Service doesn't take the ownership, but makes an own copy
-* Duplicates can be added
-* @todo should we check for duplicates and leave with KErrAlreadyExists?
-*/
-void CVCommandService::AddCommandL( const CVCommand& aCommand )
-    {
-    RUBY_DEBUG_BLOCK( "CVCommandService::AddCommandL" );
-    StartAtomicOperationLC();
-    
-    RVCommandArray commands;
-    CleanupClosePushL( commands );
-    commands.Append( &aCommand );
-    DoAddCommandsL( commands );
-    
-    CleanupStack::PopAndDestroy( &commands );
-    CleanupStack::PopAndDestroy();  // Calls EndAtomicOperation
-    }
-
-/**
-* Synchronous. Service doesn't take the ownership, but makes an own copy
-* Duplicates can be added
-* @todo Should we check for duplicates and leave with KErrAlreadyExists?
-* @param aIgnoreErrors If ETrue, even if some commands fail to be trained,
-*        handler adds all that are trainable
-*/
-void CVCommandService::AddCommandsL( const RVCommandArray& aCommands, TBool aIgnoreErrors )
-    {
-    RUBY_DEBUG_BLOCK( "CVCommandService::AddCommandsL" );
-    StartAtomicOperationLC();
-    DoAddCommandsL( aCommands, aIgnoreErrors );
-    CleanupStack::PopAndDestroy();  // Calls EndAtomicOperation
-    }
-    
-void CVCommandService::DoAddCommandsL( const RVCommandArray& aCommands, TBool aIgnoreErrors )
-    {
-    RUBY_DEBUG_BLOCKL( "CVCommandService::DoAddCommandsL" );
-    MNssContext* context = GetVCommandContextLC();
-    CTagNameSet* trainingPack = CTagNameSet::NewLC();
-    
-    for( TInt i = 0; i < aCommands.Count(); i++ )
-        {
-        CArrayPtr<MNssTag>* tags = CreateTagsLC2( *aCommands[i], *context); 
-        // tags array contains 1 tag if UserText is not defined
-        // tags array contains 2==KMaxTagsPerCommand tags if UserText is defined
-        __ASSERT_ALWAYS( tags->Count() > 0, User::Leave( KErrCorrupt ) );
-        __ASSERT_ALWAYS( tags->Count() <= KMaxTagsPerCommand, User::Leave( KErrCorrupt ) );
-        
-        // All the tags corresponding to the same VCommand get the same command id
-        SetVCommandIdL( *tags, NewCommandIdL() );
-        trainingPack->AppendL( tags->At( 0 ), aCommands[i]->SpokenText() );
-        if( tags->Count() == KMaxTagsPerCommand )
-            {
-            // UserText tag is present and this command has been converted into two tags
-            trainingPack->AppendL( tags->At( 1 ), aCommands[i]->AlternativeSpokenText() );
-            }    
-            
-        CleanupStack::Pop( tags );  // ResetAndDestroy
-        CleanupStack::PopAndDestroy( tags );  // delete the CArrayPtr itself
-        }  // for aCommands
-    
-    
-    CNssTrainingParameters* trainingParams = ConstructTrainingParametersLC();    
-    trainingPack->TrainAndSaveL( *trainingParams, *iTagManager, aIgnoreErrors );
-    CleanupStack::PopAndDestroy( trainingParams );
-    
-    CleanupStack::PopAndDestroy( trainingPack );
-    CleanupStack::PopAndDestroy( context );
-    RUBY_DEBUG0( "CVCH::DoAddCommandsL Context destroyed" );        
-    InvalidateCacheL();
-    }
-
-
-/**
-* Synchronous. Removes the command from the system
-* @param aCommand Reference to the command to be removed. Existing commands are
-*		 compared against aCommand. All the matches are removed from VAS
-* @leave KErrNotFound No such command
-*/
-void CVCommandService::RemoveCommandL( const CVCommand& aCommand )
-    {
-    RUBY_DEBUG_BLOCK( "CVCommandService::RemoveCommandL" );
-    StartAtomicOperationLC();
-	RVCommandArray array;
-	CleanupClosePushL( array );
-	array.AppendL( &aCommand );
-	DoRemoveCommandsL( array );
-	CleanupStack::PopAndDestroy( &array );
-    CleanupStack::PopAndDestroy();  // Calls EndAtomicOperation
-    }
-    
-/**
-* Synchronous. 
-* @param aCommands Reference to the list of commands to be removed. Existing commands are
-*		 compared against aCommands items. All the matches are removed from VAS
-* @param aIgnoreErrors If ETrue, even if some commands fail to be removed,
-*        handler will remove as many as possible
-*/
-void CVCommandService::RemoveCommandsL( const RVCommandArray& aCommands, TBool aIgnoreErrors )
-	{
-    RUBY_DEBUG_BLOCK( "RemoveCommandsL" );
-    StartAtomicOperationLC();
-    DoRemoveCommandsL( aCommands, aIgnoreErrors );
-    CleanupStack::PopAndDestroy();  // Calls EndAtomicOperation
-	
-	}
-    
-void CVCommandService::DoRemoveCommandsL( const RVCommandArray& aCommands,
-        						TBool aIgnoreErrors )
-	{
-	// for tracking the not found situations
-	RArray<TBool> foundCommands;
-	CleanupClosePushL( foundCommands );
-	for( TInt i=0; i < aCommands.Count(); i++ )
-	    {
-	    foundCommands.AppendL( EFalse );
-	    }
-	
-	// Iterate over all the tags in the system. Whenever a tag can be converted
-	// to one of the aCommands, move it to the deletion bunch
-	CTagNameSet* removeTags = CTagNameSet::NewLC();
-	MNssContext* context = GetVCommandContextLC();    
-	MNssTagListArray* tags = CVCommandService::GetTagListLC2( *context );
-	for( TInt i = 0; i < tags->Count(); i++ )
-		{
-		CVCommand* command = CTagCommandConverter::TagToCommandLC( *tags->At( i ) );
-		for( TInt j = 0; j < aCommands.Count(); j++ )
-			{
-			if( *command == *aCommands[j] )
-				{
-				RUBY_DEBUG1( "CVCH::RemoveCommandsL Tag [%d] should be deleted", i );
-				foundCommands[j] = ETrue;
-				removeTags->AppendL( tags->At( i ) );  
-				// ownership to removeTags, current tag to be removed from tags => index--
-				tags->Delete( i );
-				i--;
-				break;
-				}
-			}
-		CleanupStack::PopAndDestroy( command );
-		}
-
-    // Handle not founds
-    if( !aIgnoreErrors )
-        {
-        for( TInt i=0; i < foundCommands.Count(); i++ )
-            {
-            if( foundCommands[i] == EFalse )
-                {
-                RUBY_ERROR1( "Command [%d] not found", i );
-                User::Leave( KErrNotFound );
-                }
-            }
-        }
-	// Delete all the discovered tags
-	removeTags->UntrainL( *iTagManager, aIgnoreErrors );
-	
-	CleanupStack::PopAndDestroy( tags );  // ResetAndDestroy
-	CleanupStack::PopAndDestroy( tags );  // delete	
-    CleanupStack::PopAndDestroy( context );
-    CleanupStack::PopAndDestroy( removeTags );
-    CleanupStack::PopAndDestroy( &foundCommands );
-    InvalidateCacheL();
-	}
-        						
-/**
-* Synchronous
-* @return an array of the commands in the system
-*         Ownership of the array is transfered to the client
-*         The returned CVCommandArray contains copies of all the 
-*         commands currently stored in this handler
-*/
-CVCommandArray* CVCommandService::ListCommandsL()
-    {
-    RUBY_DEBUG_BLOCK( "CVCommandService::ListCommandsL" );
-    StartAtomicOperationLC();
-    if( !IsCacheValidL() )
-    	{
-    	RUBY_DEBUG0( "CVCommandService::ListCommandsL Cache is invalid. \
-    					Refresh the command list" );
-    	RefreshCommandListL();
-    	}
-    
-    CVCommandArray* result = CVCommandArray::NewL( iCommands );
-    CleanupStack::PopAndDestroy();  // Calls EndAtomicOperation
-    return result;
-    }
-
-// Private methods
-
-CVCommandService::CVCommandService( MVCommandHandlerObserver* aObserver ) :
-    iObserver( aObserver )
-    {
-    // nothing
-    }
-
-void CVCommandService::ConstructL()
-    {
-    RUBY_DEBUG_BLOCKL( "CVCommandService::ConstructL" );
-    TInt err = iLock.OpenGlobal( KCommandHandlerLockName );
-    if( err != KErrNone )
-        {
-        RUBY_DEBUG1( "CVCommandService::ConstructL failed to open mutex with [%d].\
-                      Creating a new one", err );
-        err = iLock.CreateGlobal( KCommandHandlerLockName );
-        RUBY_DEBUG1( "CVCommandService::ConstructL. Created mutex. Err [%d]", err );
-        User::LeaveIfError( err );
-        }
-    iTagPlayer = CTagPlayer::NewL();
-    iVasDbManager = CNssVASDBMgr::NewL();
-    iVasDbManager->InitializeL();
-    iTagManager = iVasDbManager->GetTagMgr();
-    TInt propertyErr = RProperty::Define( KSINDUID, ECommandHandlerTickKey, RProperty::EInt );
-    if( ( propertyErr != KErrNone ) && ( propertyErr != KErrAlreadyExists ) )
-        {
-        RUBY_ERROR1( "Attempt to define the ECommandHandlerTickKey flag failed with [%d]", 
-                     propertyErr )
-        User::Leave( propertyErr );
-        }
-    
-    RUBY_DEBUG0( "Attaching to the global tick property" );
-    User::LeaveIfError( iGlobalTickProperty.Attach( KSINDUID, ECommandHandlerTickKey ) );
-    // right after creation, local cache cannot be valid
-    TInt globalTickCount;
-    User::LeaveIfError( iGlobalTickProperty.Get( globalTickCount ) );
-    iLocalTickCount = globalTickCount - 1;
-    
-    iLastSetGlobalTickCount = iLocalTickCount;
-    iGlobalTickWatcher = CIntPropertyWatcher::NewL( KSINDUID, ECommandHandlerTickKey, *this );
-    }
-    
-/**
-* Returns the VCommand context. Creates one on demand if none exists yet
-*/
-MNssContext* CVCommandService::GetVCommandContextLC() const
-    {
-    RUBY_DEBUG0( "CVCommandService::GetVCommandContextL start" );
-    CContextProvider* contextProvider = CContextProvider::NewLC( *iVasDbManager );
-    MNssContext* result = contextProvider->GetVCommandContextLC();
-    CleanupStack::Pop( result );
-    CleanupStack::PopAndDestroy( contextProvider );
-    CleanupDeletePushL( result );
-    RUBY_DEBUG0( "CVCommandService::GetVCommandContextL end" );
-    return result;    
-    }
-    
-    
-/**
-* Constructs a set of new VAS tags from a command and a context. 
-* Does not save to VAS, just creates. Ownership on the created tag is 
-* passed to the client
-*/
-CArrayPtr<MNssTag>* CVCommandService::CreateTagsLC2( const CVCommand& aCommand, 
-                                                     const MNssContext& aContext )
-    {
-    return CTagCommandConverter::CommandToTagsLC2( aCommand, aContext, *iTagManager );
-    }
-    
-/**
-* Constructs training related parameters. Like language to be used
-* @leave negated TNssSpeechItemResult
-* @todo Is it ok to mix system-wide codes with the TNssSpeechItemResult codes
-*/
-CNssTrainingParameters* CVCommandService::ConstructTrainingParametersLC() const
-    {
-    RUBY_DEBUG0( "CVCommandService::SetLanguageParamersL start" );
-    RArray<TLanguage>* languageArray = new (ELeave) RArray<TLanguage>;
-    CleanupDeletePushL ( languageArray ); // Protect [allocated on the heap] array itself
-    CleanupClosePushL( *languageArray );  // Protect the array elements
-    
-    // Always generate a pronunciation in UI language
-    User::LeaveIfError( languageArray->Append( User::Language() ) );
-    
-    // Add an extra language, which can be determined by language identification
-    User::LeaveIfError( languageArray->Append( ELangOther ) );
-
-    CNssTrainingParameters* trainingParams = CNssTrainingParameters::NewL();
-    // No L-functions for some time, delay pushing parameters to the cleanup stack
-    
-    trainingParams->SetLanguages( languageArray );
-    // No need to protect the language array anymore. 
-    // From now on it is managed by the parameters 
-    
-    // For array elements pushed via CleanupClosePushL
-    CleanupStack::Pop( languageArray );
-    CleanupStack::Pop( languageArray );
-    CleanupStack::PushL( trainingParams );
-    RUBY_DEBUG0( "CVCommandService::SetLanguageParamersL end" );
-    return trainingParams;    
-    }
-
-/**
-* Retrieves the list of tags for a given context. Synchronous.
-* Leaves two objects on the cleanup stack!
-* First PopAndDestroy will ResetAndDestroy content
-* Second one will destroy the MNsstagListArray itself
-*/
-MNssTagListArray* CVCommandService::GetTagListLC2( const MNssContext& aContext ) const
-    {
-    RUBY_DEBUG0( "CVCommandService::GetTagListLC start" );
-    CTagGetter* tagGetter = CTagGetter::NewLC();
-    MNssTagListArray* result = tagGetter->GetTagListLC2( *iTagManager, aContext );
-
-    CleanupStack::Pop( result );
-    CleanupStack::Pop( result );
-    CleanupStack::PopAndDestroy( tagGetter );
-    CleanupDeletePushL( result );
-    CleanupResetAndDestroy<MNssTagListArray>::PushL( *result );
-    RUBY_DEBUG0( "CVCommandService::GetTagListLC end" );
-
-    return result;
-    }
-    
-/**
-* Retrieves the list of tags for a given context and voice command id. 
-* Synchronous. Leaves two objects on the cleanup stack!
-* First PopAndDestroy will ResetAndDestroy content
-* Second one will destroy the MNsstagListArray itself
-*/
-MNssTagListArray* CVCommandService::GetTagListLC2( const MNssContext& aContext, 
-                                                   TInt aCommandId ) const
-    {
-    RUBY_DEBUG0( "CVCommandService::GetTagListLC start" );
-    CTagGetter* tagGetter = CTagGetter::NewLC();
-    MNssTagListArray* result = tagGetter->GetTagListLC2( *iTagManager, aContext, aCommandId );
-
-    CleanupStack::Pop( result );
-    CleanupStack::Pop( result );
-    CleanupStack::PopAndDestroy( tagGetter );
-    CleanupDeletePushL( result );
-    CleanupResetAndDestroy<MNssTagListArray>::PushL( *result );
-    RUBY_DEBUG0( "CVCommandService::GetTagListLC end" );
-
-    return result;
-    }
-
-/**
-* Resets iCommands and fills them with the commands from VAS
-*/
-void CVCommandService::RefreshCommandListL()
-	{
-	RUBY_DEBUG_BLOCK( "CVCommandService::RefreshCommandListL" );
-	const TInt KMinimalCommandId = 0;
-	iCommands.ResetAndDestroy();
-	iMaxCommandId = KMinimalCommandId - 1;
-    MNssContext* context = GetVCommandContextLC();
-    MNssTagListArray* tagList = GetTagListLC2( *context );
-    RUBY_DEBUG1( "CVCommandService::RefreshCommandListL Found [%d] tags", tagList->Count() );
-    
-    // Sort array by command ids
-    TVCommandTagPtrArrayKey key( ECmpTInt );
-    tagList->Sort( key );
-    
-    // Array of tags related to the same VCommand
-    CArrayPtrFlat<MNssTag>* commandArray = 
-                new ( ELeave) CArrayPtrFlat<MNssTag>( KMaxTagsPerCommand ); 
-    CleanupStack::PushL( commandArray );
-    // No need for CleanupResetAndDestroyPushL. 
-    // MNssTag objects are not copied to the commandArray
-    
-    TInt currentId = KMinimalCommandId - 1;
-    
-    for( TInt i = 0; i < tagList->Count(); i++ ) 
-        {
-        RUBY_DEBUG1( "CVCommandService::RefreshCommandListL Processing tag [%d]", i );
-        TInt commandId = tagList->At( i )->RRD()->IntArray()->At( 0 );
-        if( currentId != commandId )  // new or first command
-            {
-            if( commandArray->Count() > 0  )
-                {
-                RUBY_DEBUG1( "CVCommandService::RefreshCommandListL Converting [%d] tags to command", commandArray->Count() );
-                CStoredVCommand* command = CTagCommandConverter::TagsToCommandLC( *commandArray );
-                RUBY_DEBUG2( "CVCommandService::RefreshCommandListL Converted successfully to command id [%d], command text [%S]", command->CommandId(), &(command->SpokenText() ) );
-                iCommands.AppendL( command );
-                CleanupStack::Pop( command );
-                }
-            commandArray->Reset();
-            currentId = commandId;
-            }
-        commandArray->AppendL( tagList->At( i ) );
-        iMaxCommandId = Max( iMaxCommandId, commandId );
-        }
-        
-    // Flush the last buffer
-    if( commandArray->Count() > 0  )
-        {
-        RUBY_DEBUG1( "CVCommandService::RefreshCommandListL Converting [%d] tags to command", commandArray->Count() );
-        CStoredVCommand* command = CTagCommandConverter::TagsToCommandLC( *commandArray );
-        RUBY_DEBUG2( "CVCommandService::RefreshCommandListL Converted successfully to command id [%d], command text [%S]", command->CommandId(), &(command->SpokenText() ) );
-        iCommands.AppendL( command );
-        CleanupStack::Pop( command );
-        }
-    CleanupStack::PopAndDestroy( commandArray );
-    CleanupStack::PopAndDestroy( tagList );  // ResetAndDestroy
-    CleanupStack::PopAndDestroy( tagList );  // delete
-    CleanupStack::PopAndDestroy( context );
-    MarkCacheValidL();
-	}
-	
-/**
-* Marks the iCommands as an invalid reflection of the VAS content.
-* To make iCommands reflect the real VAS content a call to 
-* RefreshCommandsL is needed
-*/
-void CVCommandService::InvalidateCacheL()
-	{
-	// Invalidating own cache means unvalidating the other instances' caches as well
-	TInt globalTickCount;
-	User::LeaveIfError( iGlobalTickProperty.Get( globalTickCount ) );
-	
-	iLocalTickCount = globalTickCount;
-    iLastSetGlobalTickCount = globalTickCount + 1;
-	User::LeaveIfError( iGlobalTickProperty.Set( iLastSetGlobalTickCount ) );
-	}
-	
-/**
-* Marks the iCommands as the valid reflection of the VAS content.
-*/
-void CVCommandService::MarkCacheValidL()
-	{
-	// Since all the cache comparison/update functions are executed under the
-	// StartAtomicOperation/EndAtomicOperation, we can be sure that nobody
-	// touched VAS and global tick count since the last IsCacheValidL
-	TInt globalTickCount;
-	User::LeaveIfError( iGlobalTickProperty.Get( globalTickCount ) );
-	
-	iLocalTickCount = globalTickCount;
-	}
-
-/**
-* Tells if the iCommands reflect the content of the VAS DB correctly
-* @return ETrue if the cache is valid, EFalse otherwise
-*/
-TBool CVCommandService::IsCacheValidL()
-	{
-	RUBY_DEBUG_BLOCKL( "CVCommandService::IsCacheValidL" );
-	TInt globalTickCount;
-	User::LeaveIfError( iGlobalTickProperty.Get( globalTickCount ) );
-	RUBY_DEBUG2( "CVCommandService::IsCacheValidL Local tick count [%d], \
-	              globalTickCount [%d]", iLocalTickCount, globalTickCount );
-	return iLocalTickCount == globalTickCount;
-	}
-
-/**
-* Generates new command id to be used for identifying voice tags, that
-* belong to the same VCommand
-*/
-TInt CVCommandService::NewCommandIdL()
-    {
-    if( !IsCacheValidL() )
-        {
-        // Fills the max used command id
-        RefreshCommandListL();
-        }
-    return ++iMaxCommandId;
-    }
-    
-/** 
-* Sets the given aId as a VCommand id for all the tags in the given list
-* This id is set as a first RRD int element of all the given MNssTags.
-* If the RRD int array has no elements yet, one element is added
-*/
-void CVCommandService::SetVCommandIdL( CArrayPtr<MNssTag>& aTags, TInt aId ) const
-    {
-    // All the tags corresponding to the same VCommand get the same command id
-    
-    for( TInt i = 0; i < aTags.Count(); i++ )
-        {
-        if( aTags[i]->RRD()->IntArray()->Count() > 0 ) 
-            {
-            aTags[i]->RRD()->IntArray()->At( i ) = aId;
-            }
-        else 
-            {
-            aTags[i]->RRD()->IntArray()->AppendL( aId );
-            }
-        }
-     }
-
-/**
-* Asynchronous
-* Attempts to play back the text expected to be recognized. 
-* To be playable command has to be added to CVCommandHandler AND
-* then retrieved back
-*
-* @param aHandler CVCommandHandler where the command is stored
-* @param aPlayEventHandler Entity that handles the playback callbacks
-* @see NssVasMPlayEventHandler.h
-*
-* @leave KErrBadHandle if the current command has not been retrieved 
-*        from CVCommandHandler (i.e. was not trained for recognition)
-* @leave KErrNotFound if this command cannot be found in aHandler
-* @leave KErrNotReady @see nssvasmspeechitem.h MNssSpeechItem::TNssSpeechItemResult 
-*                                              EVasUnexpectedRequest
-* @leave KErrInUse @see nssvasmspeechitem.h MNssSpeechItem::TNssSpeechItemResult 
-*                                              EVasInUse
-* @leave KErrArgument @see nssvasmspeechitem.h MNssSpeechItem::TNssSpeechItemResult 
-*                                              EVasInvalidParameter
-* @leave KErrGeneral @see nssvasmspeechitem.h MNssSpeechItem::TNssSpeechItemResult 
-*                                             EVasPlayFailed
-*/
-void CVCommandService::PlaySpokenTextL( const CStoredVCommand& aCommand, 
-                                        MNssPlayEventHandler& aPlayEventHandler )
-    {
-    RUBY_DEBUG_BLOCK( "CVCommandService::PlaySpokenTextL" );
-    __ASSERT_ALWAYS( !iPlaybackHandler, User::Leave( KErrInUse  ) );
-    StartAtomicOperationLC();
-    iPlaybackHandler = &aPlayEventHandler;
-    MNssTag* playbackTag = TagByCommandIdTextL( aCommand.CommandId(), 
-                                    aCommand.SpokenText() );
-    if( !playbackTag )
-        {
-        User::Leave( KErrNotFound );
-        }
-    iTagPlayer->PlayTagL( playbackTag, *this ); 
-    CleanupStack::Pop(); // EndOfAtomicOperation
-    }
-
-/**
-* Asynchronous
-* Plays back the user-specified alternative spoken text. 
-* Otherwise is identical to PlaySpokenTextL
-* @see PlaySpokenTextL
-* @leave KErrNotFound if this command cannot be found in aHandler of if 
-*        it doesn't have a user-specified text
-*/     
-void CVCommandService::PlayAlternativeSpokenTextL( const CStoredVCommand& aCommand, 
-                                        MNssPlayEventHandler& aPlayEventHandler )
-    {
-    RUBY_DEBUG_BLOCK( "CVCommandService::PlayAlternativeSpokenTextL" );
-    __ASSERT_ALWAYS( !iPlaybackHandler, User::Leave( KErrInUse  ) );
-    StartAtomicOperationLC();
-    iPlaybackHandler = &aPlayEventHandler;
-    MNssTag* playbackTag = TagByCommandIdTextL( aCommand.CommandId(), 
-                                    aCommand.AlternativeSpokenText() );
-    if( !playbackTag )
-        {
-        User::Leave( KErrNotFound );
-        }
-    iTagPlayer->PlayTagL( playbackTag, *this ); 
-    CleanupStack::Pop(); // EndOfAtomicOperation
-    }
-    
-/**
-* This method is not intended to be called directly. 
-* Use CVCommand::CancelPlaybackL instead
-* @see CVCommand::CancelPlaybackL
-* @see CStoredVCommand::CancelPlaybackL
-*/
-void CVCommandService::CancelPlaybackL( const CStoredVCommand& /*aCommand*/ )
-    {
-    // For calling EndOfAtomicOperation if a leave occurs 
-    CreateAndPushEndAtomicCleanupItemL();
-
-    __ASSERT_ALWAYS( iPlaybackHandler, User::Leave( KErrNotReady ) );
-    iTagPlayer->CancelPlaybackL();
-    iPlaybackHandler = NULL;
-    CleanupStack::PopAndDestroy(); // Calls EndAtomicOperation
-    }
-    
-/**
-* The HandlePlayStarted method is a virtual method implemented by the
-* client and is called when play is started
-* @param aDuration - the duration of the utterance data
-*/       
-void CVCommandService::HandlePlayStarted( TTimeIntervalMicroSeconds32 aDuration )
-    {
-    __ASSERT_ALWAYS( iPlaybackHandler, User::Panic( KCommandHandlerPanic, KErrNotReady ) );
-    iPlaybackHandler->HandlePlayStarted( aDuration );
-    }
-
-/**
-* The HandlePlayComplete method is a virtual method implemented by the
-* client and is called when play is completed
-* @param aErrorCode EVasErrorNone if playing was successfull
-*/       
-void CVCommandService::HandlePlayComplete( TNssPlayResult aErrorCode )
-    {
-    __ASSERT_ALWAYS( iPlaybackHandler, User::Panic( KCommandHandlerPanic, KErrNotReady ) );
-    
-    // End atomic operation before calling the observer not to block its potential
-    // VCommandHandler usage from the HandlePlayComplete
-    
-    // Before ending atomic operation, store the current event handler to the 
-    // temporary variable to protect it against the potential change by the new
-    // PlaySpokenTextL call
-    MNssPlayEventHandler* handler = iPlaybackHandler;
-    iPlaybackHandler = NULL;
-    EndAtomicOperation();
-    handler->HandlePlayComplete( aErrorCode );    
-    }
-
-    
-/**
-* Searches vcommand tags for the tag, that corresponds to the given
-* commandId and is trained against the given text
-* @param aCommandId Command id to search for
-* @param aText
-* @return ANY of the voice tags corresponding to the given aCommandId
-*         and aText. Typically there will be one such tag only. However,
-*         if there are several it is not specified which one will be 
-*         returned
-* @return NULL if no satisfying tag is found
-*/
-MNssTag* CVCommandService::TagByCommandIdTextL( TInt aCommandId, const TDesC& aText )
-    {
-    RUBY_DEBUG_BLOCKL( "CVCommandService::TagByCommandIdTextL" );
-    MNssContext* context = GetVCommandContextLC();
-    MNssTagListArray* tagList = GetTagListLC2( *context, aCommandId );
-    // A command can have up to two voice tags. We need to locate the one, 
-    // that has been trained against a given text
-    MNssTag* tag (NULL);
-    for( TInt i = 0; i < tagList->Count(); i++ )
-        {
-        if( tagList->At(i)->SpeechItem()->RawText() == aText )
-            {
-            tag = tagList->At(i);
-            // deletes pointer only. tag will be returned to the calling party
-            tagList->Delete( i );  
-            break;
-            }  // if
-        }  // for
-    CleanupStack::PopAndDestroy( tagList );  // ResetAndDestroy
-    CleanupStack::PopAndDestroy( tagList );  // delete
-    CleanupStack::PopAndDestroy( context );
-    
-    return tag;
-    }
-
-/**
-* Starts the section of the code, that can be simultaneously executed
-* only by a single instance of this class. Other instances have to wait
-* Same as starting the Java "synchronized" method. Puts the function
-* EndAtomicOperation to cleanup stack to make the use leave safe. Subsequent
-* call to CleanupStack::PopAndDestroy will run EndAtomicOperation.
-*/
-void CVCommandService::StartAtomicOperationLC()
-    {
-    RUBY_DEBUG0( "CVCommandService::StartAtomicOperation start" );
-    if ( iLock.IsHeld() )
-        {
-        User::Leave( KErrLocked );
-        }
-        
-    iLock.Wait();
-    
-    CreateAndPushEndAtomicCleanupItemL();
-    
-    RUBY_DEBUG0( "CVCommandService::StartAtomicOperation end" );
-    }
-
-/**
-* Ends the section of the code, that can be simultaneously executed
-* only by a single instance of this class. Other instances have to wait
-* Same as exiting the Java "synchronized" method
-* @leave KErrNotReady if atomic operation hasn't been started
-*/
-void CVCommandService::EndAtomicOperation()
-    {
-    RUBY_DEBUG0( "CVCommandService::EndAtomicOperation start" );
-    __ASSERT_ALWAYS( iLock.IsHeld(), User::Panic( KCommandHandlerPanic, KErrNotReady ) );
-    iLock.Signal();
-    RUBY_DEBUG0( "CVCommandService::EndAtomicOperation end" );
-    }
-    
-/**
-* Runs the EndAtomicOperation when calling CleanupStack::PopAndDestroy after
-* a call to StartAtomicOperationLC
-*/    
-void CVCommandService::CleanupEndAtomicOperation( TAny* aService )
-    {
-    CVCommandService* service = static_cast<CVCommandService*>(aService);
-    service->EndAtomicOperation();
-    }
-
-/**
-* Creates and pushes to cleanup stack a TCleanupItem that calls
-* EndAtomicOperation when CleanupStack::PopAndDestroy is called
-*/   
-void CVCommandService::CreateAndPushEndAtomicCleanupItemL()
-    {
-    TCleanupItem item( CleanupEndAtomicOperation, this );
-    CleanupStack::PushL( item );
-    }
-    
-void CVCommandService::IntValueChanged( TInt aNewValue )
-    {
-    RUBY_DEBUG2( "iLocalTickCount [%d], aNewValue [%d]", iLocalTickCount, aNewValue );
-    if( aNewValue != iLastSetGlobalTickCount )
-        {
-        if( iObserver )
-            {
-            iObserver->CommandSetChanged();
-            }  // if iObserver
-        }  // if local cache is out of date
-    }
-    
-//End of file