srsf/nssvasapi/nssvascore/src/nssvascspeechitemtrainer.cpp
branchRCL_3
changeset 19 e36f3802f733
parent 0 bf1d17376201
equal deleted inserted replaced
18:cad71a31b7fc 19:e36f3802f733
       
     1 /*
       
     2 * Copyright (c) 2004-2006 Nokia Corporation and/or its subsidiary(-ies). 
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of "Eclipse Public License v1.0"
       
     6 * which accompanies this distribution, and is available
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 *
       
    14 * Description:  The CNssSpeechItemTrainer provides methods to train, save
       
    15 *               and delete CNssSpeechItem objects in large quantities.
       
    16 *
       
    17 */
       
    18 
       
    19 
       
    20 /* Here is a state machine for training:
       
    21 *
       
    22 * Summary:
       
    23 *
       
    24 * Idle state
       
    25 *     |
       
    26 * Waiting state     <-------------------
       
    27 *     |                                | (loop back to waiting state)
       
    28 * ###################################  |
       
    29 * # IF NEEDED: Create lexicon state #  |
       
    30 * #            |                    #  |
       
    31 * # IF NEEDED: Create grammar state #---
       
    32 * #            |                    #
       
    33 * #       Training state            #
       
    34 * ###################################
       
    35 *     |
       
    36 * Idle state
       
    37 *
       
    38 *
       
    39 *
       
    40 * State: Idle state
       
    41 * Event: A client calls TrainTextL, 
       
    42 * Action:This induces a call to CNssSpeechItemTrainer::TrainTextDealyed().
       
    43 *
       
    44 *        The basic idea of _delayed_training_ is that several training calls
       
    45 *        are piled up before taking action. When a large number of names is
       
    46 *        trained at a time, the economies of scale are considerable.
       
    47 *
       
    48 *        So, TrainTextDelayed() adds the name to the to-be-trained list,
       
    49 *        and starts a _delay_timer_. When this delay timer has finished, the
       
    50 *        actual training starts.
       
    51 * Transition: Idle state -> Waiting state
       
    52 *
       
    53 *
       
    54 * State: Waiting state
       
    55 * Event: A client calls TrainTextL.
       
    56 * Action:The function adds the name to the to-be-trained list, and
       
    57 *        resets the timer
       
    58 *        (background: In contact synchronization via PC Suite, names are added
       
    59 *         every 1/2 seconds. We want to keep piling the names  as long as
       
    60 *         new names keep coming. Since we can't wait 50 seconds
       
    61 *         before training, the only reasonable solution is to reset the timer
       
    62 *         every time a new name arrives)
       
    63 * Transition: Waiting state -> Waiting state
       
    64 *
       
    65 *
       
    66 * State: Waiting state
       
    67 * Event: Timer finishes doing time.
       
    68 * Action:Check the preparations for training:
       
    69 *         * Has the grammar for the context been created?
       
    70 *         * Has the lexicon for the context been created?
       
    71 * CASE: Preconditions OK
       
    72 *       Action    : Send async AddVoiceTags call
       
    73 *       Transition: Waiting state -> Training state
       
    74 *
       
    75 * State: Training state
       
    76 * Event: Training finished
       
    77 * Action: Save the newly created Rule IDs to the speech items.
       
    78 *         Commit the database.
       
    79 *         Make the callbacks (success or failure) to the client.
       
    80 *
       
    81 * Transition: Check if new names were piled during traning.
       
    82 *         YES: Training state -> Waiting state
       
    83 *         NO : Training state -> Idle state
       
    84 *
       
    85 */
       
    86 
       
    87 #include "srsfbldvariant.hrh"
       
    88 #include "nssvascspeechitemtrainer.h"
       
    89 #include "nssvasctrainingparameters.h"
       
    90 #include "nssvascvasdatabase.h"
       
    91 #include "nssvasmsavetagclient.h"
       
    92 #include "nssvasmdeletetagclient.h"
       
    93 
       
    94 #include "rubydebug.h"
       
    95 
       
    96 #include <badesca.h>
       
    97 
       
    98 #ifdef _DEBUG
       
    99     // Used in UDEB only
       
   100     _LIT( KSpeechItemTrainerPanic, "VasCSpeechItemTrainer" );
       
   101 #endif  // _DEBUG
       
   102 
       
   103 #define DEBUGPANIC User::Panic( KSpeechItemTrainerPanic, __LINE__ )
       
   104 #define REACT( a, b ) if ( a != KErrNone ) { b; }
       
   105 #define CHECK_NOT_NULL( a ) \
       
   106     if ( !(a) ) \
       
   107         { \
       
   108         return MNssSpeechItem::EVasTrainFailed; \
       
   109         }
       
   110 #define ALLOWED_STATES( a, b, c ) \
       
   111     if ( iState != a && iState != b && iState != c ) \
       
   112         { \
       
   113         return MNssSpeechItem::EVasTrainFailed; \
       
   114         } 
       
   115 
       
   116 // tags are buffered in the buffer that grows with this granularity
       
   117 const TInt KTagBufferGranularity = 100;
       
   118 
       
   119 // rule ids are buffered in the buffer that grows with this granularity
       
   120 const TInt KRuleIdBufferGranularity = 50;
       
   121 
       
   122 // tag ids are buffered in the buffer that grows with this granularity
       
   123 const TInt KRemoveTagIdBufferGranularity = 50;
       
   124 
       
   125 // Granularity for the array of words per sinde phrase
       
   126 const TInt KSindeWordArrayGranularity = 2;
       
   127 
       
   128 
       
   129 // Local function declarations
       
   130 TInt EnforceRuleIdCountInvariant( RArray<TUint32>& aArray, TInt aCount );
       
   131 
       
   132 // ---------------------------------------------------------
       
   133 // CNssSpeechItemTrainer::CNssSpeechItemTrainer
       
   134 // C++ default constructor can NOT contain any code, that
       
   135 // might leave.
       
   136 // ---------------------------------------------------------
       
   137 //
       
   138 CNssSpeechItemTrainer::CNssSpeechItemTrainer( CNssVASDatabase* aDatabase )
       
   139 : iDatabase( aDatabase ),
       
   140   iSpeechItemBuffer       ( NULL ),
       
   141   iSpeechItemTrainingBuffer( NULL ),
       
   142   iGrammarIdBuffer        ( NULL ),
       
   143   iGrammarIdDeletingBuffer( NULL ),
       
   144   iTagBuffer(NULL)
       
   145     {
       
   146     // empty
       
   147     }
       
   148 
       
   149 
       
   150 // -----------------------------------------------------------------------------
       
   151 // CNssSpeechItemTrainer::ConstructL
       
   152 // Symbian 2nd phase constructor can leave.
       
   153 // This is overloaded function for SpeechItemTrainer from database
       
   154 // -----------------------------------------------------------------------------
       
   155 //
       
   156 void CNssSpeechItemTrainer::ConstructL()
       
   157     {
       
   158     RUBY_DEBUG_BLOCK("CNssSpeechItemTrainer::ConstructL");
       
   159     iActionTracker = CNssTrainingActionTracker::NewL( *this );
       
   160 
       
   161     // Create buffer for grouping phrases in training
       
   162     iSpeechItemBuffer = new(ELeave)RPointerArray<CNssSpeechItem>;
       
   163     iSpeechItemTrainingBuffer = 0; // No name being currently trained.
       
   164     }
       
   165 
       
   166 
       
   167 // -----------------------------------------------------------------------------
       
   168 // CNssSpeechItemTrainer::NewL
       
   169 // Two-phased constructor.
       
   170 // This is for new SpeechItemTrainer
       
   171 // -----------------------------------------------------------------------------
       
   172 //
       
   173 CNssSpeechItemTrainer* CNssSpeechItemTrainer::NewL( CNssVASDatabase* aDatabase )
       
   174     {
       
   175     RUBY_DEBUG_BLOCK( "CNssSpeechItemTrainer::NewL" );
       
   176 
       
   177     CNssSpeechItemTrainer* self = NewLC( aDatabase );
       
   178     CleanupStack::Pop( self );
       
   179     return self;
       
   180     }
       
   181 
       
   182 
       
   183 // -----------------------------------------------------------------------------
       
   184 // CNssSpeechItemTrainer::NewLC
       
   185 // Two-phased constructor.
       
   186 // This is overloaded function for SpeechItemTrainer from database
       
   187 // -----------------------------------------------------------------------------
       
   188 //
       
   189 CNssSpeechItemTrainer* CNssSpeechItemTrainer::NewLC( CNssVASDatabase* aDatabase )
       
   190     {
       
   191     CNssSpeechItemTrainer* self
       
   192         = new (ELeave) CNssSpeechItemTrainer( aDatabase );
       
   193 
       
   194     CleanupStack::PushL( self );
       
   195     self->ConstructL();
       
   196     return self;
       
   197     }
       
   198 
       
   199 // ---------------------------------------------------------
       
   200 // CNssSpeechItemTrainer::~CNssSpeechItemTrainer
       
   201 // Delete the SpeechItemTrainer object and set the Portal's 
       
   202 // state to Terminate.
       
   203 // The Trainer does not delete the Portal, the Portal  
       
   204 // deletes itself.
       
   205 // ---------------------------------------------------------
       
   206 //
       
   207 CNssSpeechItemTrainer::~CNssSpeechItemTrainer()
       
   208     {
       
   209     RUBY_DEBUG0( "CNssSpeechItemTrainer::~CNssSpeechItemTrainer" );
       
   210 
       
   211     delete iActionTracker;
       
   212 
       
   213 
       
   214     // Buffer for grouping the MNssSpeechItems for efficient training.
       
   215     if ( iSpeechItemBuffer )
       
   216         {
       
   217         iSpeechItemBuffer->Reset();
       
   218         delete iSpeechItemBuffer;
       
   219         }
       
   220 
       
   221     // Names, which are being trained by CSISpeechRecognitionUtility.
       
   222     if ( iSpeechItemTrainingBuffer )
       
   223         {
       
   224         iSpeechItemTrainingBuffer->Reset();
       
   225         delete iSpeechItemTrainingBuffer;
       
   226         }
       
   227 
       
   228     // This buffer is sent to SRS Utility. Contains: The recognition phrase split into subwords.
       
   229     iPhraseArray.ResetAndDestroy();
       
   230 
       
   231     // Training parameters
       
   232     delete iTrainingParams;
       
   233 
       
   234     // Context
       
   235     delete iContext;
       
   236 
       
   237     // Rule ID array. Return values from AddVoiceTags() are placed here.
       
   238     if ( iRuleIDArray )
       
   239         {
       
   240         iRuleIDArray->Close();
       
   241         delete iRuleIDArray;
       
   242         }
       
   243       
       
   244     if ( iDeleteRuleIDArray )
       
   245     	{
       
   246         RUBY_DEBUG0( "CNssSpeechItemTrainer::~CNssSpeechItemTrainer Deleting iDeleteRuleIDArray" );
       
   247     	iDeleteRuleIDArray->Close();
       
   248     	delete iDeleteRuleIDArray;
       
   249     	}
       
   250 
       
   251     // Handle to speech services
       
   252     if ( iSrsApi )
       
   253         {
       
   254         iSrsApi->CancelUtility();
       
   255         delete iSrsApi;
       
   256         iSrsApi = NULL;
       
   257         }
       
   258 
       
   259     // The tags to be saved: Owned by client
       
   260     // RPointerArray<CNssTag> *iTagBuffer;
       
   261     if ( iTagBuffer )
       
   262         {
       
   263         iTagBuffer->Reset();
       
   264         delete iTagBuffer;
       
   265         iTagBuffer = 0;
       
   266         }
       
   267 
       
   268     if ( iGrammarIdBuffer )
       
   269         {
       
   270         iGrammarIdBuffer->Reset();
       
   271         delete iGrammarIdBuffer;
       
   272         iGrammarIdBuffer = 0;
       
   273         }
       
   274 
       
   275     if ( iGrammarIdDeletingBuffer )
       
   276         {
       
   277         iGrammarIdDeletingBuffer->Reset();
       
   278         delete iGrammarIdDeletingBuffer;
       
   279         iGrammarIdDeletingBuffer = 0;
       
   280         }
       
   281     }
       
   282 
       
   283 // ---------------------------------------------------------
       
   284 // CNssSpeechItemTrainer::RetrainTextDelayed
       
   285 // Does delayed retraining.
       
   286 // ---------------------------------------------------------
       
   287 //
       
   288 MNssSpeechItem::TNssSpeechItemResult CNssSpeechItemTrainer::RetrainTextDelayed(
       
   289     MNssTrainTextEventHandler* aEventHandler,
       
   290 	CNssTrainingParameters*    aTrainingParams,
       
   291     CNssSpeechItem&            aSpeechItem,
       
   292     CNssContext&               aContext)
       
   293     {
       
   294     RUBY_DEBUG0( "CNssSpeechItemTrainer::RetrainTextDelayed" );
       
   295 
       
   296     // Check parameters: 
       
   297     // callback 
       
   298     CHECK_NOT_NULL( aEventHandler );
       
   299 
       
   300     // phrase to be trained
       
   301     CHECK_NOT_NULL( aSpeechItem.Text().Length() );
       
   302 
       
   303     // Check state
       
   304     ALLOWED_STATES( EStateIdle, ERetrainStateWaiting, ERetrainStateRetraining );
       
   305 
       
   306     // Check event handler
       
   307     if ( !iTrainEventHandler )
       
   308         {
       
   309         iTrainEventHandler = aEventHandler;
       
   310         }
       
   311     else if ( iTrainEventHandler != aEventHandler )
       
   312         {
       
   313         return( MNssSpeechItem::EVasTrainFailed );
       
   314         }
       
   315 
       
   316     // The training parameters and the context 
       
   317     // must be the same for all in the buffer.
       
   318     TRAPD( error,
       
   319         if ( !CheckTrainingParametersL( aTrainingParams ) ||
       
   320              !CheckContext( aContext ) )
       
   321             {
       
   322             return( MNssSpeechItem::EVasTrainFailed );
       
   323             }
       
   324          );
       
   325     if ( error != KErrNone )
       
   326         {
       
   327         return MNssSpeechItem::EVasTrainFailed;
       
   328         }
       
   329 
       
   330     // Buffer the training request
       
   331 
       
   332     // Allocate buffer, if not done earlier
       
   333     if ( !SpeechItemBufferNeeded() )
       
   334         {
       
   335         return( MNssSpeechItem::EVasTrainFailed );
       
   336         }
       
   337 
       
   338     // If this is the first tag, save Lexicon ID and Grammar ID.
       
   339     if ( iSpeechItemBuffer->Count() == 0 )
       
   340         {
       
   341         iLexiconId = aContext.LexiconId();
       
   342         iGrammarId = aContext.GrammarId();
       
   343         }
       
   344     else
       
   345         {
       
   346         // The tags after the first one must have the same Gramamr ID & Lexicon ID.
       
   347         if ( iLexiconId != aContext.LexiconId() ||
       
   348             iGrammarId != aContext.GrammarId() )
       
   349             {
       
   350             return( MNssSpeechItem::EVasTrainFailed );
       
   351             }
       
   352         }
       
   353 
       
   354     // Add request to buffer
       
   355     TInt ret = iSpeechItemBuffer->Append( &aSpeechItem );
       
   356 
       
   357     if ( ret != KErrNone )
       
   358         {
       
   359         return( MNssSpeechItem::EVasTrainFailed );
       
   360         }
       
   361 
       
   362     // Restart timer. When the timer has waited for a defined period, the names
       
   363     // get retrained. Timer is reseted every time RetrainTextDelayed is called.
       
   364     //
       
   365     // Retraining in groups is more efficient. The delay ensures this grouping.
       
   366     switch( iState )
       
   367         {
       
   368         case ERetrainStateRetraining:
       
   369             // Wait for the retraining to finish before acting.
       
   370             break;
       
   371 
       
   372         case EStateIdle:
       
   373             SetState( ERetrainStateWaiting );
       
   374             RestartTimer();
       
   375             break;
       
   376 
       
   377         case ERetrainStateWaiting:
       
   378             RestartTimer();
       
   379             break;
       
   380 
       
   381         default:
       
   382             return( MNssSpeechItem::EVasTrainFailed );
       
   383         }
       
   384 
       
   385     return( MNssSpeechItem::EVasErrorNone );
       
   386     }
       
   387 
       
   388 // ---------------------------------------------------------
       
   389 // CNssSpeechItemTrainer::SaveTagDelayed
       
   390 // Does delayed saving.
       
   391 // ---------------------------------------------------------
       
   392 //
       
   393 TInt CNssSpeechItemTrainer::SaveTagDelayed(
       
   394     MNssSaveTagClient* aSaveTagClient,
       
   395     CNssTag& aTag )
       
   396     {
       
   397     RUBY_DEBUG0( "CNssSpeechItemTrainer::SaveTagDelayed" );
       
   398 
       
   399     // Check internal state: Must not be training
       
   400     if ( this->iState != EStateIdle &&
       
   401          this->iState != ESaveStateWaiting &&
       
   402          this->iState != ESaveStateSaving )
       
   403         {
       
   404         return( KErrNotReady );
       
   405         }
       
   406 
       
   407     // Check arguments
       
   408     if ( aSaveTagClient == 0  )
       
   409         {
       
   410         return KErrArgument;
       
   411         }
       
   412 
       
   413     if ( !((CNssSpeechItem*)aTag.SpeechItem())->Trained() )
       
   414         {
       
   415         return KErrNotReady;
       
   416         }
       
   417 
       
   418     // The event handler must be the same for all group-saved tags
       
   419     if ( !iSaveEventHandler )
       
   420         {
       
   421         iSaveEventHandler = aSaveTagClient;
       
   422         }
       
   423     else if ( aSaveTagClient != iSaveEventHandler )
       
   424         {
       
   425         return KErrArgument;
       
   426         }
       
   427 
       
   428     // Buffer the saving request
       
   429 
       
   430     // Allocate buffer, if not done earlier
       
   431     if ( !iTagBuffer )
       
   432         {
       
   433         iTagBuffer = new RPointerArray<CNssTag>( KTagBufferGranularity );
       
   434 
       
   435         if ( !iTagBuffer )
       
   436             {
       
   437             return KErrNoMemory;
       
   438             }
       
   439         }
       
   440 
       
   441     // Add request to buffer
       
   442     TInt ret = iTagBuffer->Append( &aTag );
       
   443 
       
   444     if ( ret != KErrNone )
       
   445         {
       
   446         return( ret );
       
   447         }
       
   448 
       
   449     // Restart timer. When the timer has waited for a defined period, the names
       
   450     // get saved. Timer is reseted every time SaveTagDelayed is called.
       
   451     //
       
   452     // Saving in groups is more efficient. The delay ensures this grouping.
       
   453     switch( iState )
       
   454         {
       
   455         case ESaveStateSaving:
       
   456             // Wait for the training to finish before acting.
       
   457             break;
       
   458 
       
   459         case EStateIdle:
       
   460             SetState( ESaveStateWaiting );
       
   461             RestartTimer();
       
   462             break;
       
   463 
       
   464         case ESaveStateWaiting:
       
   465             RestartTimer();
       
   466             break;
       
   467 
       
   468         default:
       
   469             return( KErrCorrupt );
       
   470         }
       
   471 
       
   472     return( KErrNone );
       
   473     }
       
   474 
       
   475 // ---------------------------------------------------------
       
   476 // CNssSpeechItemTrainer::DeleteTagDelayed
       
   477 // Does delayed deleting.
       
   478 // (other items were commented in a header)
       
   479 // ---------------------------------------------------------
       
   480 //
       
   481 TInt CNssSpeechItemTrainer::DeleteTagDelayed(
       
   482     MNssDeleteTagClient* aDeleteTagClient,
       
   483     CNssTag& aTag )
       
   484     {
       
   485     RUBY_DEBUG0( "CNssSpeechItemTrainer::DeleteTagDelayed" );
       
   486 
       
   487     // Check internal state: Must not be doing something else
       
   488     ALLOWED_STATES( EStateIdle, EDeleteStateWaiting, EDeleteStateDeleting );
       
   489 
       
   490     // Check arguments
       
   491     CHECK_NOT_NULL( aDeleteTagClient );
       
   492 
       
   493     // The event handler must be the same for all group-deleted tags
       
   494     if ( !iDeleteEventHandler )
       
   495         {
       
   496         iDeleteEventHandler = aDeleteTagClient;
       
   497         }
       
   498     else if ( aDeleteTagClient != iDeleteEventHandler )
       
   499         {
       
   500         return KErrArgument;
       
   501         }
       
   502 
       
   503     // Buffer the deleting request
       
   504 
       
   505     // Allocate buffer, if not done earlier
       
   506     if ( !SpeechItemBufferNeeded() ||
       
   507          !GrammarIdBufferNeeded()  )
       
   508         {
       
   509         return( MNssSpeechItem::EVasTrainFailed );
       
   510         }
       
   511 
       
   512     // If this is the first tag, save the grammar id.
       
   513     if ( iSpeechItemBuffer->Count() == 0 )
       
   514         {
       
   515         iGrammarId = ((CNssContext*)aTag.Context())->GrammarId();
       
   516         if ( !iDeleteRuleIDArray ) 
       
   517         	{
       
   518         	iDeleteRuleIDArray = new RArray<TUint32>;
       
   519         	if( !iDeleteRuleIDArray ) 
       
   520         		{
       
   521         		return KErrNoMemory;
       
   522 	        	}
       
   523         	// no deletion. iDeleteRuleIDArray might still be used
       
   524         	}
       
   525 //        delete iDeleteRuleIDArray; // if any
       
   526 //        iDeleteRuleIDArray = new RArray<TUint32>;
       
   527         }
       
   528     else
       
   529         {
       
   530         // subsequent tags must have the same grammar id.
       
   531         if ( iGrammarId != ((CNssContext*)aTag.Context())->GrammarId() )
       
   532             {
       
   533             return( MNssSpeechItem::EVasTrainFailed );
       
   534             }
       
   535         }
       
   536 
       
   537     // Add request to buffer
       
   538     // iSpeechItemBuffer will be copied into iSpeechItemTrainingBuffer later and
       
   539     // iSpeechItemTrainingBuffer will be used to delete tags from the VAS DB
       
   540     TInt ret = iSpeechItemBuffer->Append( (CNssSpeechItem*)aTag.SpeechItem() );
       
   541     if ( ret != KErrNone )
       
   542         {
       
   543         return( MNssSpeechItem::EVasTrainFailed );
       
   544         }
       
   545 
       
   546     RUBY_DEBUG1( "CNssSpeechItemTrainer::DeleteTagDelayed Adding [%d] to iDeleteRuleIDArray", 
       
   547         ( ( CNssSpeechItem* )aTag.SpeechItem() )->RuleID() );
       
   548 
       
   549     ret = iDeleteRuleIDArray->Append( ( ( CNssSpeechItem* )aTag.SpeechItem() )->RuleID() );
       
   550 
       
   551     if ( ret != KErrNone )
       
   552         {
       
   553         RUBY_DEBUG1( "CNssSpeechItemTrainer::DeleteTagDelayed Adding to iDeleteRuleIDArray failed with error [%d]", ret );
       
   554         return( MNssSpeechItem::EVasTrainFailed );
       
   555         }
       
   556 
       
   557     // Restart timer. When the timer has waited for a defined period, the names
       
   558     // get deleted. Timer is reseted every time DeleteDagDelayed is called.
       
   559     //
       
   560     // Deleting in groups is more efficient. The delay ensures this grouping.
       
   561     switch( iState )
       
   562         {
       
   563         case EDeleteStateDeleting:
       
   564             // Wait for the training to finish before acting.
       
   565             break;
       
   566 
       
   567         case EStateIdle:
       
   568             SetState( EDeleteStateWaiting );
       
   569             RestartTimer();
       
   570             break;
       
   571 
       
   572         case EDeleteStateWaiting:
       
   573             RestartTimer();
       
   574             break;
       
   575 
       
   576         default:
       
   577             return( KErrCorrupt );
       
   578         }
       
   579 
       
   580     return( KErrNone );
       
   581     }
       
   582 
       
   583 // ---------------------------------------------------------
       
   584 // CNssSpeechItemTrainer::TrainTextDelayed
       
   585 // Does delayed training.
       
   586 // ---------------------------------------------------------
       
   587 //
       
   588 MNssSpeechItem::TNssSpeechItemResult CNssSpeechItemTrainer::TrainTextDelayed(
       
   589     MNssTrainTextEventHandler* aEventHandler,
       
   590 	CNssTrainingParameters*    aTrainingParams,
       
   591     CNssSpeechItem&            aSpeechItem,
       
   592     CNssContext&               aContext)
       
   593     {
       
   594     RUBY_DEBUG0( "CNssSpeechItemTrainer::TrainTextDelayed" );
       
   595 
       
   596     // Check parameters: 
       
   597     // callback
       
   598     CHECK_NOT_NULL( aEventHandler );
       
   599 
       
   600     // Text is not null
       
   601     CHECK_NOT_NULL( aSpeechItem.Text().Length() );
       
   602 
       
   603     // Check state
       
   604     ALLOWED_STATES( EStateIdle, ETrainStateWaiting, ETrainStateTraining );
       
   605 
       
   606     // Check event handler
       
   607     if ( !iTrainEventHandler )
       
   608         {
       
   609         iTrainEventHandler = aEventHandler;
       
   610         }
       
   611     else if ( iTrainEventHandler != aEventHandler )
       
   612         {
       
   613         return( MNssSpeechItem::EVasTrainFailed );
       
   614         }
       
   615 
       
   616     // The training parameters and the context 
       
   617     // must be the same for all in the buffer.
       
   618     TRAPD( error,
       
   619         if ( !CheckTrainingParametersL( aTrainingParams ) ||
       
   620              !CheckContext( aContext ) )
       
   621             {
       
   622             return( MNssSpeechItem::EVasTrainFailed );
       
   623             }
       
   624         );
       
   625     if ( error != KErrNone )
       
   626         {
       
   627         return MNssSpeechItem::EVasTrainFailed;
       
   628         }
       
   629 
       
   630     // Buffer the training request
       
   631     if ( !SpeechItemBufferNeeded() )
       
   632         {
       
   633         return( MNssSpeechItem::EVasTrainFailed );
       
   634         }
       
   635 
       
   636     TInt ret = iSpeechItemBuffer->Append( &aSpeechItem );
       
   637 
       
   638     if ( ret == KErrNoMemory )
       
   639         {
       
   640         return( MNssSpeechItem::EVasTrainFailed );
       
   641         }
       
   642 
       
   643     // Restart timer. When the timer has waited for a defined period, the names
       
   644     // get trained. Timer is reseted every time TrainTextDelayed is called.
       
   645     //
       
   646     // Training in groups is more efficient. The delay ensures this grouping.
       
   647     switch( iState )
       
   648         {
       
   649         case ETrainStateTraining:
       
   650             // Wait for the training to finish before acting.
       
   651             break;
       
   652 
       
   653         case EStateIdle:
       
   654             SetState( ETrainStateWaiting );
       
   655             RestartTimer();
       
   656             break;
       
   657 
       
   658         case ETrainStateWaiting:
       
   659             RestartTimer();
       
   660             break;
       
   661 
       
   662         default:
       
   663             return( MNssSpeechItem::EVasTrainFailed );
       
   664         }
       
   665 
       
   666     return( MNssSpeechItem::EVasErrorNone );
       
   667     }
       
   668 
       
   669 // ---------------------------------------------------------
       
   670 // CNssSpeechItemTrainer::HandleTrainError
       
   671 // Called if AddVoiceTags() call failed.
       
   672 // ---------------------------------------------------------
       
   673 //
       
   674 void CNssSpeechItemTrainer::HandleTrainError( RPointerArray<CNssSpeechItem>*& anItemArray )
       
   675     {
       
   676     RUBY_DEBUG0( "CNssSpeechItemTrainer::HandleTrainError" );
       
   677 
       
   678     TInt count = anItemArray->Count();
       
   679 
       
   680     CleanUpTraining();
       
   681 
       
   682     // Announce the error to the client
       
   683     for( TInt k=0; k<count; k++ )
       
   684         {
       
   685         iTrainEventHandler->HandleTrainComplete( KErrGeneral );
       
   686         
       
   687         }
       
   688     iTrainEventHandler = NULL;
       
   689     // All the errors reported, everything was rolled back
       
   690     // Back tothe idle state
       
   691     SetState( EStateIdle );
       
   692     }
       
   693 
       
   694 // ---------------------------------------------------------
       
   695 // CNssSpeechItemTrainer::CleanUpTrianing
       
   696 // Cleans memory allocated by training.
       
   697 // ---------------------------------------------------------
       
   698 //
       
   699 void CNssSpeechItemTrainer::CleanUpTraining(void)
       
   700     {
       
   701     // Delete buffered names
       
   702     if ( iSpeechItemTrainingBuffer )
       
   703         {
       
   704         iSpeechItemTrainingBuffer->Close();
       
   705         }
       
   706     delete iSpeechItemTrainingBuffer;
       
   707     iSpeechItemTrainingBuffer = 0;
       
   708 
       
   709     // Delete parameters common to all names
       
   710     delete iTrainingParams;
       
   711     iTrainingParams = 0;
       
   712 
       
   713     delete iContext;
       
   714     iContext = 0;
       
   715     }
       
   716 
       
   717 // ---------------------------------------------------------
       
   718 // CNssSpeechItemTrainer::DoTrainTextDelayed
       
   719 // Starts training tags. Sends the AddVoiceTags() call.
       
   720 // ---------------------------------------------------------
       
   721 //
       
   722 void CNssSpeechItemTrainer::DoTrainTextDelayed()
       
   723     {
       
   724     SetState( ETrainStateTraining );
       
   725 
       
   726     // Move from speech item buffers from filling state to processing state.
       
   727 
       
   728     // names to be trained + names to be retrained
       
   729     iSpeechItemTrainingBuffer = iSpeechItemBuffer;
       
   730     iSpeechItemBuffer = 0;
       
   731 
       
   732     // Initialize iSrsApi (speech recognition utility)
       
   733     TInt error = CreateSrsApi();
       
   734     if ( error != KErrNone )
       
   735         {
       
   736         RUBY_DEBUG1( "CNssSpeechItemTrainer::DoTrainTextDelayed Creating SrsApi failed. Error [%d]", error );
       
   737         HandleTrainError( iSpeechItemTrainingBuffer );
       
   738         }
       
   739     else 
       
   740        	{
       
   741         	
       
   742 	    __ASSERT_DEBUG( iContext->LexiconId() != KInvalidLexiconID, 
       
   743 	                    User::Panic( KSpeechItemTrainerPanic, KErrCorrupt ) );
       
   744 	    __ASSERT_DEBUG( iContext->GrammarId() != KInvalidGrammarID, 
       
   745 	                    User::Panic( KSpeechItemTrainerPanic, KErrCorrupt ) );
       
   746 
       
   747 	    // Extract texts from speech items to phrase array.
       
   748 
       
   749 	    // iPhraseArray is an array of arrays: 
       
   750 	    // 
       
   751 	    //        |-- firstname1
       
   752 	    //  tag1 -|-- lastname1
       
   753 	    //
       
   754 	    //  tag2 -|-- firstname2
       
   755 	    //        |-- lastname2
       
   756 	    iPhraseArray.ResetAndDestroy();
       
   757 
       
   758 	    // Convert speech item array to the format understood by the Utility.
       
   759 	    TInt ret = SpeechItems2Phrases( *iSpeechItemTrainingBuffer, iPhraseArray );
       
   760 	    if ( ret != KErrNone )
       
   761 	        {
       
   762 	        SendTrainingCallbacks( ret );
       
   763 	        /** @todo reengineer into signle return path
       
   764 	            @todo check that everything is cleaned up before the return */
       
   765 	        return;
       
   766 	        }
       
   767 
       
   768 	    // Initialize Rule ID array. The Utility puts the IDs
       
   769 	    // of newly created rules here.
       
   770 	    // Not using (ELeave) since this is non-leaving function (trapping of (ELeave) is not allowed).
       
   771 	    iRuleIDArray = new RArray<TUint32>;
       
   772 
       
   773 	    if ( iRuleIDArray == 0 )
       
   774 	        {
       
   775             RUBY_DEBUG0( "CNssSpeechItemTrainer::DoTrainTextDelayed iRuleIDArray == 0" );
       
   776 
       
   777 	        HandleTrainError( iSpeechItemTrainingBuffer );
       
   778 	        }
       
   779 	    else
       
   780 	       	{
       
   781             RUBY_DEBUG1( "CNssSpeechItemTrainer::Calling AddVoiceTags (%d names)", 
       
   782                          iPhraseArray.Count() ); 
       
   783 	       	// allocation succeeded
       
   784 
       
   785             TRAPD( errSinde, const RArray<RTrainingLanguageArray>& languages = 
       
   786                                         iTrainingParams->SindeLanguagesL() );
       
   787             
       
   788             if ( errSinde == KErrNone )
       
   789                 {
       
   790 #ifdef __SINDE_TRAINING
       
   791                 TRAP_IGNORE(
       
   792                     const RArray<RTrainingLanguageArray>& languages = 
       
   793                                         iTrainingParams->SindeLanguagesL();
       
   794     		        ret = iSrsApi->AddVoiceTags( iPhraseArray,
       
   795                                                  languages,
       
   796                                                  (TSILexiconID)iContext->LexiconId(),
       
   797                                                  (TSIGrammarID)iContext->GrammarId(),
       
   798                                                  *iRuleIDArray );
       
   799                 ); // TRAP_IGNORE
       
   800 #endif // __SINDE_TRAINING
       
   801                 }
       
   802             else
       
   803                 {
       
   804                 // Use the old style of training if SINDE languages are not available
       
   805 		        ret = iSrsApi->AddVoiceTags( iPhraseArray,
       
   806                                              iTrainingParams->Languages(),
       
   807                                              (TSILexiconID)iContext->LexiconId(),
       
   808                                              (TSIGrammarID)iContext->GrammarId(),
       
   809                                              *iRuleIDArray );
       
   810                 }
       
   811 
       
   812 		    // error -> cleanup
       
   813 		    if ( ret != KErrNone )
       
   814 		        {
       
   815                 RUBY_DEBUG1( "CNssSpeechItemTrainer::AddVoiceTags failed(%d)", ret );
       
   816 
       
   817 		        HandleTrainComplete( ret );
       
   818 		        }  // if ret is not KErrNone
       
   819 	       	}  // if iRuleIDArray allocation succeeded
       
   820        	}  // if SRS API was created successfully
       
   821     }
       
   822 
       
   823 // ---------------------------------------------------------
       
   824 // CNssSpeechItemTrainer::DoRetrainTextDelayed
       
   825 // Starts the 1st phase of retraining,
       
   826 // which is removing old rules.
       
   827 // ---------------------------------------------------------
       
   828 //
       
   829 void CNssSpeechItemTrainer::DoRetrainTextDelayed()
       
   830     {
       
   831     __ASSERT_DEBUG( iSpeechItemBuffer != 0, DEBUGPANIC );
       
   832 
       
   833     SetState( ERetrainStateRetraining );
       
   834 
       
   835     // Move speech item buffer from filling state to processing state.
       
   836     iSpeechItemTrainingBuffer = iSpeechItemBuffer;
       
   837     iSpeechItemBuffer = 0;
       
   838 
       
   839     // Initialize iSrsApi (speech recognition utility)
       
   840     TInt error = CreateSrsApi();
       
   841     if ( error != KErrNone )
       
   842         {
       
   843         RUBY_DEBUG1( "CNssSpeechItemTrainer::DoRetrainTextDelayed Creating SrsApi failed. Error [%d]", error );
       
   844         HandleTrainError( iSpeechItemTrainingBuffer );
       
   845         return;
       
   846         }
       
   847 
       
   848     // Start deleting tags
       
   849     iTagDeleteCounter = 0;
       
   850     DeleteNextTag();
       
   851     }
       
   852 
       
   853 // ---------------------------------------------------------
       
   854 // CNssSpeechItemTrainer::DoRetrainAddVoiceTags
       
   855 // Phase 2 of retraining: Add voice tags
       
   856 // ---------------------------------------------------------
       
   857 //
       
   858 void CNssSpeechItemTrainer::DoRetrainAddVoiceTags()
       
   859     {
       
   860     SetState( ERetrainStateRetraining );
       
   861 
       
   862     // Move from speech item buffers from filling state to processing state.
       
   863 
       
   864     __ASSERT_DEBUG( iContext->LexiconId() != KInvalidLexiconID, 
       
   865                     User::Panic( KSpeechItemTrainerPanic, KErrCorrupt ) );
       
   866     __ASSERT_DEBUG( iContext->GrammarId() != KInvalidGrammarID, 
       
   867                     User::Panic( KSpeechItemTrainerPanic, KErrCorrupt ) );
       
   868 
       
   869     // Extract texts from speech items to phrase array.
       
   870 
       
   871     iPhraseArray.ResetAndDestroy();
       
   872 
       
   873     // Convert speech item array to the format understood by the Utility.
       
   874     TInt ret = SpeechItems2Phrases( *iSpeechItemTrainingBuffer, iPhraseArray );
       
   875     if ( ret != KErrNone )
       
   876         {
       
   877         SendTrainingCallbacks( ret );
       
   878         return;
       
   879         }
       
   880 
       
   881     // Allocate Rule ID array. The Utility fills this array.
       
   882     // When the utility trans a name, it attaches a Rule ID to the name.
       
   883     iRuleIDArray = new RArray<TUint32>;
       
   884     if ( iRuleIDArray == 0 )
       
   885         {
       
   886         SendTrainingCallbacks( KErrNoMemory );
       
   887         return;
       
   888         }
       
   889 
       
   890     RUBY_DEBUG1( "CNssSpeechItemTrainer::Retrain Calling AddVoiceTags (%d names)", 
       
   891                  iPhraseArray.Count() );
       
   892 
       
   893     TRAPD( errSinde, const RArray<RTrainingLanguageArray>& languages = 
       
   894                                         iTrainingParams->SindeLanguagesL() );
       
   895             
       
   896     if ( errSinde == KErrNone )
       
   897         {
       
   898 #ifdef __SINDE_TRAINING        	
       
   899         TRAP_IGNORE(
       
   900             const RArray<RTrainingLanguageArray>& languages = 
       
   901                                 iTrainingParams->SindeLanguagesL();
       
   902 	        ret = iSrsApi->AddVoiceTags( iPhraseArray,
       
   903                                          languages,
       
   904                                          (TSILexiconID)iContext->LexiconId(),
       
   905                                          (TSIGrammarID)iContext->GrammarId(),
       
   906                                          *iRuleIDArray );
       
   907         ); // TRAP_IGNORE
       
   908 #endif // __SINDE_TRAINING
       
   909         }
       
   910     else
       
   911         {
       
   912         // Use the old style of training if SINDE languages are not available
       
   913         ret = iSrsApi->AddVoiceTags( iPhraseArray,
       
   914                                      iTrainingParams->Languages(),
       
   915                                      (TSILexiconID)iLexiconId,
       
   916                                      (TSIGrammarID)iGrammarId,
       
   917                                      *iRuleIDArray );
       
   918         }
       
   919 
       
   920     // error -> cleanup
       
   921     if ( ret != KErrNone )
       
   922         {
       
   923         RUBY_DEBUG1( "CNssSpeechItemTrainer::Retrain ERROR: AddVoiceTags(%d)", ret );
       
   924 
       
   925         SendTrainingCallbacks( ret );
       
   926         }
       
   927 
       
   928     }
       
   929 
       
   930 // ---------------------------------------------------------
       
   931 // CNssSpeechItemTrainer::DoRetrainAddVoiceTags
       
   932 // After the new tags have been trained:
       
   933 // Announce the new rule IDs for speech items,
       
   934 // and update the rule IDs to the VAS database.
       
   935 // ---------------------------------------------------------
       
   936 //
       
   937 void CNssSpeechItemTrainer::HandleRetrainComplete( TInt aResult )
       
   938     {
       
   939     RUBY_DEBUG1( "CNssSpeechItemTrainer::HandleTrainComplete(%d)", aResult );
       
   940 
       
   941     // iRuleIdArray contains the rule IDs of the newly trained tags.
       
   942     // The following call makes sure that
       
   943     // iRuleIdArray.Count() == iSpeechItemTrainingBuffer.Count().
       
   944     if ( EnforceRuleIdCountInvariant( *iRuleIDArray, 
       
   945                         iSpeechItemTrainingBuffer->Count() ) != KErrNone )
       
   946         {
       
   947         SendTrainingCallbacks( KErrNoMemory );
       
   948         }
       
   949     else
       
   950         {
       
   951         TInt count = iSpeechItemTrainingBuffer->Count();
       
   952         RArray<TNssSpeechItem> ruleIdUpdateArray( KRuleIdBufferGranularity );
       
   953 
       
   954         for( TInt itemIdx = 0; itemIdx < count; itemIdx++ )
       
   955             {
       
   956             CNssSpeechItem* item = (*iSpeechItemTrainingBuffer)[itemIdx];
       
   957             TUint32    ruleID = (*iRuleIDArray)[itemIdx];
       
   958             if ( ruleID != KInvalidRuleID )
       
   959                 {
       
   960                 // tag was trained successfully
       
   961 
       
   962                 item->DelayedTrainingComplete( ruleID );
       
   963                 
       
   964                 TNssSpeechItem flatItem;
       
   965 
       
   966                 flatItem.iRuleId = item->RuleID();
       
   967                 flatItem.iTagId  = item->TagId();
       
   968 
       
   969                 TInt ret = ruleIdUpdateArray.Append( flatItem );
       
   970 
       
   971                 if ( ret != KErrNone )
       
   972                     {
       
   973                     ruleIdUpdateArray.Close();
       
   974                     SendTrainingCallbacks( KErrNoMemory );
       
   975                     return;
       
   976                     }
       
   977                 }
       
   978             else
       
   979                 {
       
   980                 // training failed -> remove tag
       
   981                 iDatabase->DeleteTag( item->TagId() );
       
   982                 }   
       
   983             }
       
   984 
       
   985         aResult = iDatabase->UpdateTagRuleIDs( ruleIdUpdateArray );
       
   986         ruleIdUpdateArray.Close();
       
   987         SendTrainingCallbacks( aResult );
       
   988         }
       
   989 
       
   990     
       
   991     }
       
   992 
       
   993 // ---------------------------------------------------------
       
   994 // CNssSpeechItemTrainer::DoSaveTags
       
   995 // Saves tags.
       
   996 // ---------------------------------------------------------
       
   997 //
       
   998 void CNssSpeechItemTrainer::DoSaveTags()
       
   999     {
       
  1000 
       
  1001     __ASSERT_DEBUG( iState == ESaveStateWaiting, DEBUGPANIC );
       
  1002 
       
  1003     // Save the tags en masse
       
  1004     TInt ret = iDatabase->SaveTags( iTagBuffer );
       
  1005 
       
  1006     // Next, we're going to make callbacks to the client.
       
  1007     // Before that, we have to return the object to idle state,
       
  1008     // This way, the last callback can trigger new train/save action.
       
  1009 
       
  1010     // Destroy buffered tags
       
  1011     TInt count = iTagBuffer->Count();
       
  1012     iTagBuffer->Close();
       
  1013     delete iTagBuffer;
       
  1014     iTagBuffer = 0;
       
  1015 
       
  1016     // Detach save tag client
       
  1017     MNssSaveTagClient* client = iSaveEventHandler;
       
  1018     iSaveEventHandler = 0;
       
  1019 
       
  1020     // Make SpeechItemTrainer ready for new challenges
       
  1021     SetState( EStateIdle );
       
  1022 
       
  1023     // Make callbacks
       
  1024     for ( TInt k = 0; k < count; k++ )
       
  1025         {
       
  1026         if ( ret == KErrNone )
       
  1027             {
       
  1028 #ifdef _DEBUG
       
  1029             TRAPD( err, client->SaveTagCompleted( KErrNone ) );
       
  1030             __ASSERT_DEBUG( err == KErrNone, DEBUGPANIC );
       
  1031 #else
       
  1032             client->SaveTagCompleted( KErrNone );
       
  1033 #endif // _DEBUG
       
  1034             }
       
  1035         else
       
  1036             {
       
  1037 #ifdef _DEBUG
       
  1038             TRAPD( err, client->SaveTagCompleted( KErrGeneral ) );
       
  1039             __ASSERT_DEBUG( err == KErrNone, DEBUGPANIC );
       
  1040 #else
       
  1041             client->SaveTagCompleted( KErrGeneral );
       
  1042 #endif // _DEBUG
       
  1043             }
       
  1044         }
       
  1045     }
       
  1046 
       
  1047 // ---------------------------------------------------------
       
  1048 // CNssSpeechItemTrainer::DoDeleteTags
       
  1049 // Starts tag removal.
       
  1050 // ---------------------------------------------------------
       
  1051 //
       
  1052 void CNssSpeechItemTrainer::DoDeleteTags()
       
  1053     {
       
  1054     // NOTE: This method is never called from anywhere!
       
  1055     
       
  1056     SetState( EDeleteStateDeleting );
       
  1057 
       
  1058     TInt err = CreateSrsApi();
       
  1059     if ( err != KErrNone )
       
  1060         {
       
  1061         RemoveTagsFinished( err );
       
  1062         return;
       
  1063         }
       
  1064 
       
  1065     // Move Tag Buffer from filling state to processing state.
       
  1066     iSpeechItemTrainingBuffer = iSpeechItemBuffer;
       
  1067     iSpeechItemBuffer = 0;
       
  1068     iSpeechItemBuffer = new RPointerArray<CNssSpeechItem>; // New filling buffer
       
  1069     if( !iSpeechItemBuffer )
       
  1070         {
       
  1071         SendTrainingCallbacks( KErrNoMemory );
       
  1072         return;
       
  1073         }
       
  1074 
       
  1075     iTagDeleteCounter = 0;
       
  1076     DeleteNextTag();
       
  1077     }
       
  1078 
       
  1079 // ---------------------------------------------------------
       
  1080 // CNssSpeechItemTrainer::DoDeleteGroupedTags
       
  1081 // Starts grouped tag removal.
       
  1082 // Used when deleting tags without retraining.
       
  1083 // ---------------------------------------------------------
       
  1084 //
       
  1085 void CNssSpeechItemTrainer::DoDeleteGroupedTags()
       
  1086     {
       
  1087   	RUBY_DEBUG1("CNssSpeechItemTrainer::DoDeleteGroupedTags iDeleteRuleIDArray->Count() = [%d]", iDeleteRuleIDArray->Count() );
       
  1088 	SetState( EDeleteStateDeleting );
       
  1089 
       
  1090     // Move Tag Buffer from filling state to processing state.
       
  1091     // We want to have this buffer != NULL so that we are able to do callbacks (with appropriate error code )
       
  1092     // in RemoveTagsFinished method even if e.g. CreateSrsApi fails. 
       
  1093     iSpeechItemTrainingBuffer = iSpeechItemBuffer;
       
  1094     iSpeechItemBuffer = 0;
       
  1095 
       
  1096     TInt err = CreateSrsApi();
       
  1097     if ( err != KErrNone )
       
  1098         {
       
  1099         RemoveTagsFinished( err );
       
  1100         return;
       
  1101         }
       
  1102 
       
  1103     iSpeechItemBuffer = new RPointerArray<CNssSpeechItem>; // New filling buffer
       
  1104     
       
  1105     if( !iSpeechItemBuffer )
       
  1106         {
       
  1107         // As this method is not used when retraining, no need 
       
  1108         // to send other callbacks than those related to deleting tags.
       
  1109         RemoveTagsFinished( KErrNoMemory );
       
  1110         return;
       
  1111         }
       
  1112 
       
  1113 	TInt ret = iSrsApi->RemoveRules( ( TSIGrammarID )iGrammarId,
       
  1114                                      *iDeleteRuleIDArray );
       
  1115 
       
  1116     if ( ret != KErrNone && ret != KErrNotFound )
       
  1117         {
       
  1118         RUBY_DEBUG1( "CNssSpeechItemTrainer::DoDeleteGroupedTags RemoveRules failed. \
       
  1119                       Error [%d]", ret );
       
  1120         RemoveTagsFinished( ret );
       
  1121         return;
       
  1122         }
       
  1123 
       
  1124     }
       
  1125 
       
  1126 // ---------------------------------------------------------
       
  1127 // CNssSpeechItemTrainer::DeleteNextTag
       
  1128 // Sends a RemoveRule() call for the next rule in the removal queue.
       
  1129 // ---------------------------------------------------------
       
  1130 //
       
  1131 void CNssSpeechItemTrainer::DeleteNextTag()
       
  1132     {
       
  1133     RUBY_DEBUG2( "CNssSpeechItemTrainer::DeleteNextTag iTagDeleteCounter [%d], iSpeechItemTrainingBuffer->Count() [%d]", iTagDeleteCounter, iSpeechItemTrainingBuffer->Count() );
       
  1134 
       
  1135     __ASSERT_DEBUG( iTagDeleteCounter <= iSpeechItemTrainingBuffer->Count(), 
       
  1136                     User::Panic( KSpeechItemTrainerPanic, __LINE__ ) );
       
  1137 
       
  1138     CNssSpeechItem* speechItem = (*iSpeechItemTrainingBuffer)[iTagDeleteCounter];
       
  1139 
       
  1140     TInt ret = iSrsApi->RemoveRule(
       
  1141         (TSIGrammarID)speechItem->GrammarId(),
       
  1142         (TSIRuleID)speechItem->RuleID()
       
  1143         );
       
  1144 
       
  1145     if ( ret != KErrNone && ret != KErrNotFound )
       
  1146         {
       
  1147         RemoveTagsFinished( ret );
       
  1148         return;
       
  1149         }
       
  1150     }
       
  1151 
       
  1152 
       
  1153 // ---------------------------------------------------------
       
  1154 // CNssSpeechItemTrainer::HandleRemoveTagComplete
       
  1155 // Called after SRS has successfully removed a tag.
       
  1156 // ---------------------------------------------------------
       
  1157 //
       
  1158 void CNssSpeechItemTrainer::HandleRemoveTagComplete()
       
  1159     {
       
  1160     iTagDeleteCounter++;
       
  1161 
       
  1162     if ( iTagDeleteCounter < iSpeechItemTrainingBuffer->Count() )
       
  1163         {
       
  1164         DeleteNextTag();
       
  1165         }
       
  1166     else
       
  1167         {
       
  1168         RemoveTagsFinished( KErrNone );
       
  1169         return;
       
  1170         }
       
  1171     }
       
  1172     
       
  1173 // ---------------------------------------------------------
       
  1174 // CNssSpeechItemTrainer::HandleRemoveTagsComplete
       
  1175 // Called after SRS has successfully removed a group of tags.
       
  1176 // ---------------------------------------------------------
       
  1177 //
       
  1178 void CNssSpeechItemTrainer::HandleRemoveTagsComplete()
       
  1179     {
       
  1180     RemoveTagsFinished( KErrNone );
       
  1181     }
       
  1182 
       
  1183 // ---------------------------------------------------------
       
  1184 // CNssSpeechItemTrainer::HandleRemoveTagFailed
       
  1185 // Called if SRS fails to remove a tag.
       
  1186 // ---------------------------------------------------------
       
  1187 //
       
  1188 void CNssSpeechItemTrainer::HandleRemoveTagFailed( TInt aError )
       
  1189     {
       
  1190     RemoveTagsFinished( aError );
       
  1191     }
       
  1192 
       
  1193 // ---------------------------------------------------------
       
  1194 // CNssSpeechItemTrainer::RemoveTagsFinished
       
  1195 // All required tags have been removed.
       
  1196 // Go to next phase.
       
  1197 //    functions a bit defferently depending on whether we were retraining or
       
  1198 //    deleting tags
       
  1199 // ---------------------------------------------------------
       
  1200 //
       
  1201 void CNssSpeechItemTrainer::RemoveTagsFinished( TInt aSuccess )
       
  1202     {
       
  1203     // The continuation depends on what we are doing:
       
  1204 
       
  1205     // If we are deleting tags
       
  1206     if ( iState == EDeleteStateDeleting )
       
  1207         {
       
  1208         if ( aSuccess == KErrNone )
       
  1209             {
       
  1210             RemoveTagsFromVAS();
       
  1211             }
       
  1212         else{
       
  1213             FinishDeleteTags( aSuccess );
       
  1214             }
       
  1215         }
       
  1216 
       
  1217     // If we are retraining 
       
  1218     // (removing the old rules before adding the new ones)
       
  1219     else if ( iState == ERetrainStateRetraining )
       
  1220         {
       
  1221         if  ( aSuccess == KErrNone )
       
  1222             {
       
  1223             DoRetrainAddVoiceTags();
       
  1224             }
       
  1225         else{
       
  1226             SendTrainingCallbacks( aSuccess );
       
  1227             }
       
  1228         }
       
  1229     else
       
  1230         {
       
  1231         RUBY_DEBUG1( "CNssSpeechItemTrainer::RemoveTagsFinished - ERROR: Wrong state(%d)", iState );
       
  1232         }
       
  1233     }
       
  1234 
       
  1235 // ---------------------------------------------------------
       
  1236 // CNssSpeechItemTrainer::RemoveTagsFromVAS
       
  1237 // Deletes tags from VAS.
       
  1238 // ---------------------------------------------------------
       
  1239 //
       
  1240 void CNssSpeechItemTrainer::RemoveTagsFromVAS()
       
  1241     {
       
  1242     RArray<TUint32> tagIdArray( KRemoveTagIdBufferGranularity );
       
  1243     TInt ret = KErrNone;
       
  1244 
       
  1245     ////////////// Remove tags from VAS DB ///////////////////
       
  1246 
       
  1247     // Take the Tag IDs to an array.
       
  1248     for ( TInt k( 0 ); k < iSpeechItemTrainingBuffer->Count(); k++ )
       
  1249         {
       
  1250         ret |= tagIdArray.Append( (*iSpeechItemTrainingBuffer)[k]->TagId() );
       
  1251         }
       
  1252 
       
  1253     // Delete tags from VAS DB
       
  1254     if ( ret == KErrNone )
       
  1255         {
       
  1256         ret = iDatabase->DeleteTags( tagIdArray );
       
  1257         }
       
  1258 
       
  1259     // Close tag ID array.
       
  1260     tagIdArray.Close();
       
  1261 
       
  1262     ////////////// Remove tags from VAS DB done //////////////
       
  1263 
       
  1264     FinishDeleteTags( KErrNone );
       
  1265     }
       
  1266 
       
  1267 // ---------------------------------------------------------
       
  1268 // CNssSpeechItemTrainer::FinishDeleteTags
       
  1269 // Cleans up and sends calbacks after
       
  1270 // deleting has finished or completed.
       
  1271 // ---------------------------------------------------------
       
  1272 //
       
  1273 void CNssSpeechItemTrainer::FinishDeleteTags( TInt aSuccess )
       
  1274     {
       
  1275     RUBY_DEBUG1("CNssSpeechItemTrainer::FinishDeleteTags aSuccess [%d]", aSuccess);
       
  1276     // Commit or uncommit according to success
       
  1277     if ( iSrsApi )
       
  1278         {
       
  1279         if ( aSuccess == KErrNone )
       
  1280             {
       
  1281             CommitSIUpdate();
       
  1282             }
       
  1283         else{
       
  1284             UncommitSIUpdate();
       
  1285             }
       
  1286         }
       
  1287 	
       
  1288     // Free memory
       
  1289     TInt count( 0 );
       
  1290     if ( iSpeechItemTrainingBuffer )
       
  1291         {        
       
  1292         count = iSpeechItemTrainingBuffer->Count();
       
  1293         RUBY_DEBUG1("CNssSpeechItemTrainer::FinishDeleteTags aSuccess Freeing [%d] items from the training buffer", count);
       
  1294         iSpeechItemTrainingBuffer->Close();
       
  1295         }
       
  1296     delete iSpeechItemTrainingBuffer;
       
  1297     iSpeechItemTrainingBuffer = 0;
       
  1298 
       
  1299     // Send callbacks
       
  1300     MNssDeleteTagClient* client = iDeleteEventHandler;
       
  1301     iDeleteEventHandler = 0;
       
  1302     iTagDeleteCounter = 0;
       
  1303 
       
  1304     
       
  1305     for ( TInt k( 0 ); k < count; k++ )
       
  1306         {
       
  1307         RUBY_DEBUG1("CNssSpeechItemTrainer::FinishDeleteTags sending callback for item [%d]", k);
       
  1308         // Failed or succeedeed, one rule is processed
       
  1309         iDeleteRuleIDArray->Remove(0);
       
  1310        
       
  1311         client->DeleteTagCompleted( aSuccess );
       
  1312         }
       
  1313     RUBY_DEBUG2("CNssSpeechItemTrainer::FinishDeleteTags Reported [%d] deletions. [%d] remaining. Setting idle state", count, iDeleteRuleIDArray->Count());
       
  1314     SetState( EStateIdle );
       
  1315 
       
  1316     }
       
  1317 
       
  1318 // ---------------------------------------------------------
       
  1319 // CNssSpeechItemTrainer::RunBufferedActionsL
       
  1320 // Called when it is time to execute the buffered actions
       
  1321 // ---------------------------------------------------------
       
  1322 //
       
  1323 void CNssSpeechItemTrainer::RunBufferedActionsL()
       
  1324     {
       
  1325     RUBY_DEBUG_BLOCK( "CNssSpeechItemTrainer::RunL" );
       
  1326     
       
  1327     if ( iState == ETrainStateWaiting )
       
  1328         {
       
  1329         DoTrainTextDelayed();
       
  1330         }
       
  1331     else if ( iState == ESaveStateWaiting )
       
  1332         {
       
  1333         DoSaveTags();
       
  1334         }
       
  1335     else if ( iState == EDeleteStateWaiting )
       
  1336         {
       
  1337         DoDeleteGroupedTags();
       
  1338         }
       
  1339     else if ( iState == ERetrainStateWaiting )
       
  1340         {
       
  1341         DoRetrainTextDelayed();
       
  1342         }
       
  1343     else
       
  1344         {
       
  1345         RUBY_DEBUG1( "CNssSpeechItemTrainer::RunL - ERROR: Wrong state (%d)", iState );
       
  1346         }
       
  1347     }
       
  1348 
       
  1349 // ---------------------------------------------------------
       
  1350 // CNssSpeechItemTrainer::RestartTimer
       
  1351 // Restarts the timer.
       
  1352 // ---------------------------------------------------------
       
  1353 //
       
  1354 void CNssSpeechItemTrainer::RestartTimer()
       
  1355     {
       
  1356     TRAP_IGNORE( iActionTracker->ActionRequestedL() );
       
  1357     }
       
  1358 
       
  1359 // ---------------------------------------------------------
       
  1360 // CNssSpeechItemTrainer::CheckTrainingParametersL
       
  1361 // All tags in the queue should have the same training parameters. This
       
  1362 // function check that a new context has similar training parameters
       
  1363 // as the previous ones.
       
  1364 // ---------------------------------------------------------
       
  1365 //
       
  1366 TBool CNssSpeechItemTrainer::CheckTrainingParametersL( const CNssTrainingParameters* aParams )
       
  1367     {
       
  1368     if ( aParams )
       
  1369         {
       
  1370         if ( !iTrainingParams )
       
  1371             {
       
  1372             // Make a local copy of training parameters
       
  1373             iTrainingParams = CNssTrainingParameters::NewL();
       
  1374 
       
  1375             const RArray<TLanguage>& paramLangArray = aParams->Languages();
       
  1376 
       
  1377             RArray<TLanguage>* langArray = new ( ELeave ) RArray<TLanguage>;
       
  1378             CleanupStack::PushL( langArray );
       
  1379                 
       
  1380             for ( TInt k = 0; k < paramLangArray.Count(); k++ )
       
  1381                 {
       
  1382                 TInt ret = langArray->Append( paramLangArray[ k ] );
       
  1383                 if ( ret != KErrNone )
       
  1384                     {
       
  1385                     langArray->Close();
       
  1386                     delete langArray;
       
  1387                     return EFalse;
       
  1388                     }
       
  1389                 }
       
  1390                 
       
  1391             // Copy training languages
       
  1392             iTrainingParams->SetLanguages( langArray );
       
  1393             CleanupStack::Pop( langArray );
       
  1394 
       
  1395             // Copy SINDE languages
       
  1396             TRAP_IGNORE( iTrainingParams->SetSindeLanguages( aParams->SindeLanguagesL() ) );
       
  1397             
       
  1398             // Copy separator
       
  1399             iTrainingParams->SetSeparator( aParams->Separator() );
       
  1400             }
       
  1401         else
       
  1402             {
       
  1403             // Compare with previous training parameters
       
  1404             
       
  1405             // Separator
       
  1406             if ( aParams->Separator() != iTrainingParams->Separator() )
       
  1407                 {
       
  1408                 return EFalse;
       
  1409                 }
       
  1410 
       
  1411             // Training languages
       
  1412             for ( TInt k = 0; k < aParams->Languages().Count(); k++ )
       
  1413                 {
       
  1414                 if ( aParams->Languages()[ k ] != iTrainingParams->Languages()[ k ] )
       
  1415                     {
       
  1416                     return EFalse;
       
  1417                     }
       
  1418                 }
       
  1419             
       
  1420             // @todo SINDE languages should be checked also!            
       
  1421             }
       
  1422        }
       
  1423        
       
  1424     return ETrue;
       
  1425     }
       
  1426 
       
  1427 // ---------------------------------------------------------
       
  1428 // CNssSpeechItemTrainer::CheckContext
       
  1429 // All tags in the queue should have the same contexts. This
       
  1430 // function check that a new context is similar to that of previous tags.
       
  1431 // ---------------------------------------------------------
       
  1432 //
       
  1433 TBool CNssSpeechItemTrainer::CheckContext(CNssContext& aContext)
       
  1434     {
       
  1435     if ( &aContext == 0 ) // Default settings - anything goes.
       
  1436         {
       
  1437         return( EFalse );
       
  1438         }
       
  1439 
       
  1440     if ( aContext.RecognitionMode() != ENSSSdSiMode &&
       
  1441          aContext.RecognitionMode() != ENSSSiMode )
       
  1442         {
       
  1443         return( EFalse );
       
  1444         }
       
  1445 
       
  1446     if ( iContext )
       
  1447         {
       
  1448         // Check that identifiers (name & ID) are identical.
       
  1449         if ( aContext.ContextId() != iContext->ContextId() )
       
  1450             {
       
  1451             return( EFalse );
       
  1452             }
       
  1453 
       
  1454         if ( aContext.ContextName().Compare( iContext->ContextName() ) != 0 )
       
  1455             {
       
  1456             return( EFalse );
       
  1457             }
       
  1458         }
       
  1459     else
       
  1460         {
       
  1461         if ( aContext.RecognitionMode()  == ENSSSdSiMode )
       
  1462             {
       
  1463             aContext.SetRecognitionMode( ENSSSiMode );
       
  1464             }
       
  1465 
       
  1466         TRAPD( error, iContext = aContext.CopyL() );
       
  1467         if ( error != KErrNone )
       
  1468             {
       
  1469             return EFalse;
       
  1470             }
       
  1471         }
       
  1472 
       
  1473     return( ETrue );
       
  1474     }
       
  1475 
       
  1476 // ---------------------------------------------------------
       
  1477 // CNssSpeechItemTrainer::HandleTrainComplete
       
  1478 // Called after speech recognition utility has trained all tags.
       
  1479 // Announces the newly assigned Rule IDs for the speech items.
       
  1480 // Signals the VAS client that training has been finished.
       
  1481 // ---------------------------------------------------------
       
  1482 //
       
  1483 void CNssSpeechItemTrainer::HandleTrainComplete( TInt aResult )
       
  1484     {
       
  1485     RUBY_DEBUG1( "CNssSpeechItemTrainer::HandleTrainComplete(%d)", aResult );
       
  1486 
       
  1487     // iRuleIdArray contains the rule IDs of the newly trained tags.
       
  1488     // The following call makes sure that
       
  1489     // iRuleIdArray.Count() == iSpeechItemTrainingBuffer.Count().
       
  1490     if ( EnforceRuleIdCountInvariant( *iRuleIDArray, 
       
  1491               iSpeechItemTrainingBuffer->Count() ) != KErrNone )
       
  1492         {
       
  1493         SendTrainingCallbacks( KErrNoMemory );
       
  1494         }
       
  1495 
       
  1496     // Save rule IDs. Some rule IDs may have "KInvalidRuleID". This is a sign
       
  1497     // that training failed. It's good to save also that info to speech items.
       
  1498     for( TInt itemIdx = 0; itemIdx < iSpeechItemTrainingBuffer->Count(); itemIdx++ )
       
  1499         {
       
  1500         CNssSpeechItem* item = (*iSpeechItemTrainingBuffer)[ itemIdx ];
       
  1501         TUint32    ruleID = (*iRuleIDArray)[ itemIdx ];
       
  1502 
       
  1503         item->DelayedTrainingComplete( ruleID );
       
  1504         }
       
  1505 
       
  1506     SendTrainingCallbacks( aResult );
       
  1507     }
       
  1508 
       
  1509 // ---------------------------------------------------------
       
  1510 // CNssSpeechItemTrainer::SendTrainingCallbacks
       
  1511 // 
       
  1512 // ---------------------------------------------------------
       
  1513 //
       
  1514 void CNssSpeechItemTrainer::SendTrainingCallbacks( TInt aResult )
       
  1515     {
       
  1516     // If the changes were successful, commit them.
       
  1517     // If they werent, roll back the changes.
       
  1518     if ( aResult == KErrNone )
       
  1519         {
       
  1520         CommitSIUpdate();
       
  1521         }
       
  1522     else{
       
  1523         UncommitSIUpdate();
       
  1524         }
       
  1525 
       
  1526     // Save count (callback count)...
       
  1527     TInt count = iSpeechItemTrainingBuffer->Count();
       
  1528     MNssTrainTextEventHandler* callback = iTrainEventHandler;
       
  1529     RArray<TUint32>* ruleIdArray = iRuleIDArray;
       
  1530     iRuleIDArray = 0;
       
  1531 
       
  1532     // Delete buffered names that were just trained
       
  1533     if ( iSpeechItemTrainingBuffer )
       
  1534         {
       
  1535         iSpeechItemTrainingBuffer->Close();
       
  1536         }
       
  1537     delete iSpeechItemTrainingBuffer;
       
  1538     iSpeechItemTrainingBuffer = 0;
       
  1539 
       
  1540 
       
  1541     // If there are names on the training queue,
       
  1542     // restart the waiting of delayed training.
       
  1543     if ( iSpeechItemBuffer && iSpeechItemBuffer->Count() > 0 )
       
  1544         {
       
  1545         // don't delete context etc as training will be continued
       
  1546         SetState( ETrainStateWaiting );
       
  1547         RestartTimer();
       
  1548         }
       
  1549     else
       
  1550         {
       
  1551         SetState( EStateIdle );
       
  1552             
       
  1553         // Cleanup
       
  1554         delete iTrainingParams;
       
  1555         iTrainingParams = 0;
       
  1556 
       
  1557         delete iContext;
       
  1558         iContext = 0;
       
  1559         
       
  1560         iTrainEventHandler = 0;        
       
  1561         }
       
  1562 
       
  1563     // Make the callbacks to the client according to the recognition result.
       
  1564     for( TInt k( 0 ); k < count; k++ )
       
  1565         {
       
  1566         if ( ruleIdArray->Count() <= k )
       
  1567             {
       
  1568             RUBY_DEBUG2( "CNssSpeechItemTrainer::SendTrainingCallbacks ruleIdArray->Count() [%d] <= k [%d]", ruleIdArray->Count(), k );
       
  1569             callback->HandleTrainComplete( KErrNoMemory );
       
  1570             }
       
  1571         if ( (*ruleIdArray)[ k ] == KInvalidRuleID )
       
  1572             {
       
  1573             RUBY_DEBUG0( "CNssSpeechItemTrainer::SendTrainingCallbacks (*ruleIdArray)[ k ] == KInvalidRuleID" );
       
  1574             if ( aResult == KErrNone )
       
  1575                 {
       
  1576                 callback->HandleTrainComplete( KErrGeneral );
       
  1577                 }
       
  1578             else
       
  1579                 {
       
  1580                 callback->HandleTrainComplete( aResult );
       
  1581                 }
       
  1582             
       
  1583             }
       
  1584         else
       
  1585             {
       
  1586             callback->HandleTrainComplete( KErrNone );
       
  1587             }
       
  1588         }
       
  1589 
       
  1590     ruleIdArray->Close();
       
  1591     delete ruleIdArray;
       
  1592     ruleIdArray = 0;
       
  1593     }
       
  1594 
       
  1595 // ---------------------------------------------------------
       
  1596 // CNssSpeechItemTrainer::MsruoEvent
       
  1597 // SRS Utility callback function 
       
  1598 // ---------------------------------------------------------
       
  1599 //
       
  1600 void CNssSpeechItemTrainer::MsruoEvent( TUid aEvent, TInt aResult )
       
  1601     {
       
  1602     switch( aEvent.iUid )
       
  1603         {
       
  1604         case KUidAsrEventAddVoiceTagsVal:
       
  1605             RUBY_DEBUG0( "CNssSpeechItemTrainer::MsruoEvent - state is KUidAsrEventAddVoiceTagsVal" );
       
  1606 
       
  1607             if ( iState == ETrainStateTraining )
       
  1608                 {
       
  1609                 HandleTrainComplete( aResult );
       
  1610                 }
       
  1611             else if ( iState == ERetrainStateRetraining )
       
  1612                 {
       
  1613                 HandleRetrainComplete( aResult );
       
  1614                 }
       
  1615             break;
       
  1616 
       
  1617         case KUidAsrEventRemoveRuleVal:
       
  1618             RUBY_DEBUG0( "CNssSpeechItemTrainer::MsruoEvent - state is KUidAsrEventRemoveRuleVal" );
       
  1619 
       
  1620             if ( aResult == KErrNone || aResult == KErrNotFound )
       
  1621                 {
       
  1622                 HandleRemoveTagComplete();
       
  1623                 }
       
  1624             else{
       
  1625                 HandleRemoveTagFailed( aResult );
       
  1626                 }
       
  1627             break;
       
  1628             
       
  1629         case KUidAsrEventRemoveRulesVal:
       
  1630             RUBY_DEBUG0( "CNssSpeechItemTrainer::MsruoEvent - state is KUidAsrEventRemoveRulesVal" );
       
  1631 
       
  1632         	if( aResult == KErrNone || aResult == KErrNotFound )
       
  1633         		{
       
  1634         		HandleRemoveTagsComplete();
       
  1635         		}
       
  1636         	else 
       
  1637         		{
       
  1638         		HandleRemoveTagFailed( aResult );
       
  1639         		}
       
  1640         	break;
       
  1641 
       
  1642         default:
       
  1643             RUBY_DEBUG2( "CNssSpeechItemTrainer::MsruoEvent - ERROR: Uknown state (%d,%d)", aEvent.iUid, aResult );
       
  1644             break;
       
  1645         }
       
  1646     }
       
  1647 
       
  1648 // ---------------------------------------------------------
       
  1649 // CNssSpeechItemTrainer::SplitPhraseSindeL
       
  1650 // Splits a phrase to parts. Returns the parts in array.
       
  1651 // ---------------------------------------------------------
       
  1652 //
       
  1653 CDesC16ArrayFlat* CNssSpeechItemTrainer::SplitPhraseSindeL( const TDesC& aPhrase, 
       
  1654                                                             TChar aSeparator )
       
  1655     {
       
  1656     CDesC16ArrayFlat* wordArray = new ( ELeave ) CDesC16ArrayFlat( KSindeWordArrayGranularity );
       
  1657     CleanupStack::PushL( wordArray );
       
  1658 
       
  1659     // Separate the words in the phrase.
       
  1660     TPtrC text = aPhrase; // Cursor to the phrase
       
  1661 
       
  1662     do
       
  1663         {
       
  1664         TInt index = text.Locate( aSeparator );
       
  1665 
       
  1666         if ( index != 0 )
       
  1667             {
       
  1668             // no more separators -> this is the last word -> end of word == end of string
       
  1669             if ( index == KErrNotFound ) 
       
  1670                 {
       
  1671                 index = text.Length();
       
  1672                 }
       
  1673 
       
  1674                 // Add word to array
       
  1675                 wordArray->AppendL( text.Left( index ) );
       
  1676                 }
       
  1677 
       
  1678         // Discard the processed word
       
  1679         TInt charactersLeft = text.Length() - index; 
       
  1680         // Forget the separator
       
  1681         if ( charactersLeft > 0 )                    
       
  1682             {
       
  1683             charactersLeft--;                        
       
  1684             }
       
  1685 
       
  1686         // Update text cursor
       
  1687         text.Set( text.Right( charactersLeft ) );
       
  1688 
       
  1689         } 
       
  1690     while( text.Length() > 0 );
       
  1691 
       
  1692     CleanupStack::Pop( wordArray );
       
  1693     return wordArray;
       
  1694     }
       
  1695 
       
  1696 // ---------------------------------------------------------
       
  1697 // CNssSpeechItemTrainer::SplitPhrase
       
  1698 // Splits a phrase to parts. Returns the parts in array.
       
  1699 // ---------------------------------------------------------
       
  1700 //
       
  1701 CDesC16ArrayFlat* CNssSpeechItemTrainer::SplitPhraseL( const TDesC& aPhrase, TChar aSeparator )
       
  1702     {
       
  1703     CDesC16ArrayFlat *wordArray = new (ELeave) CDesC16ArrayFlat( KSindeWordArrayGranularity );
       
  1704 
       
  1705     // Separate the words in the phrase. Especially firstname / lastname.
       
  1706     TPtrC text = aPhrase; // Cursor to the phrase
       
  1707 
       
  1708     do
       
  1709         {
       
  1710         TInt index = text.Locate( aSeparator );
       
  1711 
       
  1712         // no more separators -> this is the last word -> end of word == end of string
       
  1713         if ( index == -1 ) 
       
  1714             {
       
  1715             index = text.Length();
       
  1716             }
       
  1717 
       
  1718         // Add word to array
       
  1719         wordArray->AppendL( text.Left( index ) );
       
  1720 
       
  1721         // Discard the processed word
       
  1722         TInt charactersLeft = text.Length() - index; 
       
  1723         // Forget the separator
       
  1724         // (the last word doesn't have one)
       
  1725         if ( charactersLeft > 0 )                    
       
  1726             {
       
  1727             charactersLeft--;                        
       
  1728             }
       
  1729 
       
  1730         // Update text cursor
       
  1731         text.Set( text.Right( charactersLeft ) );
       
  1732 
       
  1733         } 
       
  1734     while( text.Length() > 0 );
       
  1735 
       
  1736     return wordArray;
       
  1737     }
       
  1738 
       
  1739 // ---------------------------------------------------------
       
  1740 // CNssSpeechItemTrainer::CommitSIUpdate
       
  1741 // Commits changes to SRS and destroys SRS utility.
       
  1742 // ---------------------------------------------------------
       
  1743 //
       
  1744 TInt CNssSpeechItemTrainer::CommitSIUpdate()
       
  1745     {
       
  1746     if ( !iSrsApi )
       
  1747         {
       
  1748         return( KErrNotReady );
       
  1749         }
       
  1750 
       
  1751     iSrsApi->CommitChanges();
       
  1752 
       
  1753     delete iSrsApi;
       
  1754     iSrsApi = NULL;
       
  1755 
       
  1756     return( KErrNone );
       
  1757     }
       
  1758 
       
  1759 // ---------------------------------------------------------
       
  1760 // CNssSpeechItemTrainer::UncommitSIUpdate
       
  1761 // Destroys SRS utility without committing.
       
  1762 // ---------------------------------------------------------
       
  1763 //
       
  1764 TInt CNssSpeechItemTrainer::UncommitSIUpdate()
       
  1765     {
       
  1766     if ( !iSrsApi )
       
  1767         {
       
  1768         return( KErrNotReady );
       
  1769         }
       
  1770 
       
  1771     delete iSrsApi;
       
  1772     iSrsApi = NULL;
       
  1773 
       
  1774     return( KErrNone );
       
  1775     }
       
  1776 
       
  1777 // ---------------------------------------------------------
       
  1778 // CNssSpeechItemTrainer::SpeechItemBufferNeeded
       
  1779 // Trys to allocate a speech item buffer
       
  1780 // ---------------------------------------------------------
       
  1781 //
       
  1782 TBool CNssSpeechItemTrainer::SpeechItemBufferNeeded()
       
  1783     {
       
  1784     if ( !iSpeechItemBuffer )
       
  1785         {
       
  1786         iSpeechItemBuffer = new RPointerArray<CNssSpeechItem>;
       
  1787         if ( !iSpeechItemBuffer )
       
  1788             {
       
  1789             return( EFalse );
       
  1790             }
       
  1791         }
       
  1792 
       
  1793     return( ETrue );
       
  1794     }
       
  1795 
       
  1796 // ---------------------------------------------------------
       
  1797 // CNssSpeechItemTrainer::SpeechItemBufferNeeded
       
  1798 // Trys to allocate a grammar id buffer
       
  1799 // ---------------------------------------------------------
       
  1800 //
       
  1801 TBool CNssSpeechItemTrainer::GrammarIdBufferNeeded()
       
  1802     {
       
  1803     if ( !iGrammarIdBuffer )
       
  1804         {
       
  1805         iGrammarIdBuffer = new RArray<TUint32>;
       
  1806         if ( !iGrammarIdBuffer )
       
  1807             {
       
  1808             return( EFalse );
       
  1809             }
       
  1810         }
       
  1811 
       
  1812     return( ETrue );
       
  1813     }
       
  1814 
       
  1815 // ---------------------------------------------------------
       
  1816 // CNssSpeechItemTrainer::SpeechItemBufferNeeded
       
  1817 // Trys to create SRS api. Returns success status.
       
  1818 // ---------------------------------------------------------
       
  1819 //
       
  1820 TInt CNssSpeechItemTrainer::CreateSrsApi()
       
  1821     {
       
  1822     if ( !iSrsApi )
       
  1823         {
       
  1824         TRAPD( err, iSrsApi = CNssSiUtilityWrapper::NewL( *this, KNssVASApiUid ) );
       
  1825         REACT( err, return( err ) );
       
  1826 
       
  1827         iSrsApi->SetEventHandler( this );
       
  1828         }
       
  1829 
       
  1830     return KErrNone;
       
  1831     }
       
  1832 
       
  1833 
       
  1834 // ---------------------------------------------------------
       
  1835 // CNssSpeechItemTrainer::SpeechItems2Phrases
       
  1836 // Converts an array of speech items
       
  1837 // into Utility's AddVoiceTags array format.
       
  1838 // ---------------------------------------------------------
       
  1839 //
       
  1840 TInt CNssSpeechItemTrainer::SpeechItems2Phrases(
       
  1841     RPointerArray<CNssSpeechItem>& aSpeechItems,
       
  1842     RPointerArray<MDesCArray>& aPhrases )
       
  1843     {
       
  1844     // iPhraseArray is an array of arrays: 
       
  1845     // 
       
  1846     //        |-- firstname1
       
  1847     //  tag1 -|-- lastname1
       
  1848     //
       
  1849     //  tag2 -|-- firstname2
       
  1850     //        |-- lastname2
       
  1851 
       
  1852     // Create training parameters, if none were given
       
  1853     if ( iTrainingParams == 0 )
       
  1854         {
       
  1855         RArray<TLanguage>* languages = new RArray<TLanguage>();
       
  1856 
       
  1857         if ( !languages )
       
  1858             {
       
  1859             return( KErrNoMemory );
       
  1860             }
       
  1861 
       
  1862         // Use UI language + 1 other as default if languages are not given
       
  1863         // in training parameters
       
  1864         TInt err = languages->Append( User::Language() );
       
  1865 
       
  1866         if ( err == KErrNone )
       
  1867             {
       
  1868             err = languages->Append( ELangOther );
       
  1869             }
       
  1870 
       
  1871         if ( err != KErrNone )
       
  1872             {
       
  1873             languages->Close();
       
  1874             delete languages;
       
  1875             return( err );
       
  1876             }
       
  1877 
       
  1878         TRAP( err, iTrainingParams = CNssTrainingParameters::NewL() ); 
       
  1879         if ( err != KErrNone )
       
  1880             {
       
  1881             languages->Close();
       
  1882             delete languages;
       
  1883             return( err );
       
  1884             }
       
  1885 
       
  1886         iTrainingParams->SetLanguages( languages );
       
  1887         }
       
  1888 
       
  1889     // Split the phrases to subwords (names -> first name + last name)
       
  1890     for ( TInt k( 0 ); k < aSpeechItems.Count(); k++ )
       
  1891         {
       
  1892         // Split names into the first name and the last name
       
  1893         CDesC16ArrayFlat *wordArray = 0;
       
  1894 
       
  1895         // Check if SINDE type of training should be used
       
  1896         TRAPD( errSinde, const RArray<RTrainingLanguageArray>& temp = 
       
  1897                                         iTrainingParams->SindeLanguagesL() );
       
  1898         if ( errSinde == KErrNone )
       
  1899             {
       
  1900             TRAP_IGNORE( wordArray = SplitPhraseSindeL( aSpeechItems[ k ]->RawText(),
       
  1901                                                         iTrainingParams->Separator() ) );
       
  1902             }
       
  1903         else
       
  1904             {
       
  1905             TRAP_IGNORE( wordArray = SplitPhraseL( aSpeechItems[ k ]->Text(),
       
  1906                                                    iTrainingParams->Separator() ) );
       
  1907             }
       
  1908 
       
  1909         if ( wordArray == 0 )
       
  1910             {
       
  1911             return KErrNoMemory;
       
  1912             }
       
  1913 
       
  1914         TInt ret = aPhrases.Append( wordArray );
       
  1915 
       
  1916         if ( ret != KErrNone )
       
  1917             {
       
  1918             return ret;
       
  1919             }
       
  1920         }
       
  1921 
       
  1922     return( KErrNone );
       
  1923     }
       
  1924     
       
  1925 // ---------------------------------------------------------
       
  1926 // CNssSpeechItemTrainer::SetState
       
  1927 // Changes state of the trainer
       
  1928 // ---------------------------------------------------------
       
  1929 //
       
  1930 void CNssSpeechItemTrainer::SetState(TTrainState aState) 
       
  1931 	{
       
  1932 	RUBY_DEBUG2("CNssSpeechItemTrainer::SetState Switching state from [%d] to [%d]", iState, aState);
       
  1933 #ifdef _DEBUG
       
  1934 	if( iState == EDeleteStateWaiting ) 
       
  1935 		{
       
  1936 		RUBY_DEBUG0("CNssSpeechItemTrainer::SetState From EDeleteStateWaiting");
       
  1937 		}
       
  1938 	if( aState == EDeleteStateWaiting ) 
       
  1939 		{
       
  1940 		RUBY_DEBUG0("CNssSpeechItemTrainer::SetState To EDeleteStateWaiting");
       
  1941 		}
       
  1942 		
       
  1943 #endif	
       
  1944 	iState = aState;
       
  1945 	}
       
  1946 
       
  1947 // ---------------------------------------------------------
       
  1948 // CNssSpeechItemTrainer::EnforceRuleIdCountInvariant
       
  1949 // Adds KInvalidRuleId to the Rule ID Array, until
       
  1950 // the number of rules is equal to count.
       
  1951 // ---------------------------------------------------------
       
  1952 //
       
  1953 TInt EnforceRuleIdCountInvariant( RArray<TUint32>& aArray, TInt aCount )
       
  1954     {
       
  1955     while( aArray.Count() < aCount )
       
  1956         {
       
  1957         TInt err = aArray.Append( KInvalidRuleID );
       
  1958         if ( err != KErrNone )
       
  1959             {
       
  1960             return( err );
       
  1961             }
       
  1962         }
       
  1963 
       
  1964     return KErrNone;
       
  1965     }