upstream version 1.2.2
[debian/freetts] / com / sun / speech / engine / BaseEngine.java
1 /**
2  * Copyright 1998-2001 Sun Microsystems, Inc.
3  * 
4  * See the file "license.terms" for information on usage and
5  * redistribution of this file, and for a DISCLAIMER OF ALL 
6  * WARRANTIES.
7  */
8 package com.sun.speech.engine;
9
10 import java.util.Collection;
11 import java.util.Iterator;
12
13 import javax.speech.AudioException;
14 import javax.speech.AudioManager;
15 import javax.speech.Engine;
16 import javax.speech.EngineEvent;
17 import javax.speech.EngineException;
18 import javax.speech.EngineListener;
19 import javax.speech.EngineModeDesc;
20 import javax.speech.EngineProperties;
21 import javax.speech.EngineStateError;
22 import javax.speech.SpeechEvent;
23 import javax.speech.VocabManager;
24
25 /**
26  * Supports the JSAPI 1.0 <code>Engine</code> interface.
27  * Actual JSAPI implementations might want to extend or modify this
28  * implementation.
29  */
30 abstract public class BaseEngine implements Engine, SpeechEventDispatcher {
31     /**
32      * A bitmask holding the current state of this <code>Engine</code>.
33      */
34     protected long             engineState;
35
36     /**
37      * An <code>Object</code> used for synchronizing access to
38      * <code>engineState</code>.
39      * @see #engineState
40      */
41     protected Object           engineStateLock;
42
43     /**
44      * List of <code>EngineListeners</code> registered for
45      * <code>EngineEvents</code> on this <code>Engine</code>.
46      */
47     protected Collection      engineListeners;
48
49     /**
50      * The <code>AudioManager</code> for this <code>Engine</code>.
51      */
52     protected AudioManager     audioManager = null;
53
54     /**
55      * The <code>EngineModeDesc</code> for this <code>Engine</code>.
56      */
57     protected EngineModeDesc   engineModeDesc = null;
58
59     /**
60      * The <code>EngineProperties</code> for this <code>Engine</code>.
61      */
62     protected EngineProperties engineProperties = null;
63
64     /**
65      * Utility state for clearing the <code>engineState</code>.
66      */
67     protected final static long CLEAR_ALL_STATE = ~(0L);
68
69     /**
70      * Creates a new <code>Engine</code> in the
71      * <code>DEALLOCATED</code> state.
72      */
73     public BaseEngine() {
74         this(null);
75     }
76
77     /**
78      * Creates a new <code>Engine</code> in the
79      * <code>DEALLOCATED</code> state.
80      *
81      * @param desc the operating mode of this <code>Engine</code>
82      */
83     public BaseEngine(EngineModeDesc desc) {
84         engineModeDesc = desc;
85         engineListeners = new java.util.ArrayList();
86         engineState = DEALLOCATED;
87         engineStateLock = new Object();
88         engineProperties = createEngineProperties();
89     }
90     
91     /** 
92      * Returns a or'ed set of flags indicating the current state of
93      * this <code>Engine</code>.
94      *
95      * <p>An <code>EngineEvent</code> is issued each time this
96      * <code>Engine</code> changes state.
97      *
98      * <p>The <code>getEngineState</code> method can be called successfully
99      * in any <code>Engine</code> state.
100      *
101      * @return the current state of this <code>Engine</code>
102      *
103      * @see #getEngineState
104      * @see #waitEngineState
105      */
106     public long getEngineState() {
107         return engineState;
108     }
109     
110     /** 
111      * Blocks the calling thread until this <code>Engine</code>
112      * is in a specified state.
113      *
114      * <p>All state bits specified in the <code>state</code> parameter
115      * must be set in order for the method to return, as defined
116      * for the <code>testEngineState</code> method.  If the <code>state</code>
117      * parameter defines an unreachable state
118      * (e.g. <code>PAUSED | RESUMED</code>) an exception is thrown.
119      *
120      * <p>The <code>waitEngineState</code> method can be called successfully
121      * in any <code>Engine</code> state.
122      *
123      * @param state a bitmask of the state to wait for
124      *
125      * @see #testEngineState
126      * @see #getEngineState
127      *
128      * @throws InterruptedException
129      *   if another thread has interrupted this thread.
130      * @throws IllegalArgumentException
131      *   if the specified state is unreachable
132      */
133     public void waitEngineState(long state) 
134         throws InterruptedException, IllegalArgumentException {
135         synchronized (engineStateLock) {
136             while (!testEngineState(state))
137                 engineStateLock.wait();
138         }
139     }    
140
141     /** 
142      * Returns <code>true</code> if this state of this
143      * <code>Engine</code> matches the specified state.
144      *
145      * <p>The test performed is not an exact match to the current
146      * state.  Only the specified states are tested.  For
147      * example the following returns true only if the
148      * <code>Synthesizer</code> queue is empty, irrespective
149      * of the pause/resume and allocation states.
150      * 
151      * <PRE>
152      *    if (synth.testEngineState(Synthesizer.QUEUE_EMPTY)) ...
153      * </PRE>
154      *
155      * <p>The <code>testEngineState</code> method is equivalent to:
156      * 
157      * <PRE>
158      *      if ((engine.getEngineState() & state) == state)
159      * </PRE>
160      *
161      * <p>The <code>testEngineState</code> method can be called 
162      * successfully in any <code>Engine</code> state.
163      *
164      * @param state a bitmask of the states to test for
165      *
166      * @return <code>true</code> if this <code>Engine</code> matches
167      *   <code>state</code>; otherwise <code>false</code>
168      * @throws IllegalArgumentException
169      *   if the specified state is unreachable
170      */
171     public boolean testEngineState(long state) 
172         throws IllegalArgumentException {
173         return ((getEngineState() & state) == state);
174     }
175
176     /**
177      * Updates this <code>Engine</code> state by clearing defined bits,
178      * then setting other specified bits.
179      *
180      * @return a length-2 array with old and new state values.
181      */
182     protected long[] setEngineState(long clear, long set) {
183         long states[] = new long[2];        
184         synchronized (engineStateLock) {
185             states[0] = engineState;
186             engineState = engineState & (~clear);
187             engineState = engineState | set;
188             states[1] = engineState;
189             engineStateLock.notifyAll();
190         }        
191         return states;
192     }
193
194     /** 
195      * Allocates the resources required for this <code>Engine</code> and
196      * puts it into the <code>ALLOCATED</code> state.  When this method
197      * returns successfully the <code>ALLOCATED</code> bit of this
198      * <code>Engine</code> state is set, and the
199      * <code>testEngineState(Engine.ALLOCATED)</code> method returns
200      * <code>true</code>.
201      *
202      * <p>During the processing of the method, this <code>Engine</code> is
203      * temporarily in the <code>ALLOCATING_RESOURCES</code> state.
204      *
205      * @see #deallocate
206      *
207      * @throws EngineException if this <code>Engine</code> cannot be allocated
208      * @throws EngineStateError if this <code>Engine</code> is in the
209      *   <code>DEALLOCATING_RESOURCES</code> state
210      */
211      public void allocate() throws EngineException, EngineStateError {
212      if (testEngineState(ALLOCATED)) {
213             return;
214         }
215
216         long[] states = setEngineState(CLEAR_ALL_STATE, ALLOCATING_RESOURCES);
217         postEngineAllocatingResources(states[0], states[1]);
218
219         handleAllocate();        
220     }
221
222     /**
223      * Called from the <code>allocate</code> method.  Override this in
224      * subclasses.
225      *
226      * @see #allocate
227      *
228      * @throws EngineException if problems are encountered
229      */
230     abstract protected void handleAllocate() throws EngineException;
231
232     /** 
233      * Frees the resources of this <code>Engine</code> that were
234      * acquired during allocation and during operation and return this
235      * <code>Engine</code> to the <code>DEALLOCATED</code>.  When this
236      * method returns the <code>DEALLOCATED</code> bit of this
237      * <code>Engine</code> state is set so the
238      * <code>testEngineState(Engine.DEALLOCATED)</code> method returns 
239      * <code>true</code>.
240      *
241      * <p>During the processing of the method, this
242      * <code>Engine</code> is temporarily in the
243      * <code>DEALLOCATING_RESOURCES</code> state.
244      *
245      * <p>A deallocated engine can be re-started with a subsequent
246      * call to <code>allocate</code>.
247      *
248      * @see #allocate
249      *
250      * @throws EngineException if this <code>Engine</code> cannot be
251      *   deallocated
252      * @throws EngineStateError if this <code>Engine</code> is in the
253      *   <code>ALLOCATING_RESOURCES</code> state
254      */
255     public void deallocate() throws EngineException, EngineStateError {
256         if (testEngineState(DEALLOCATED)) {
257             return;
258         }
259
260         long[] states = setEngineState(CLEAR_ALL_STATE,
261                                        DEALLOCATING_RESOURCES);
262         postEngineDeallocatingResources(states[0], states[1]);
263
264         handleDeallocate();
265     }
266
267     /**
268      * Called from the <code>deallocate</code> method.  Override this in
269      * subclasses.
270      *  
271      * @throws EngineException if this <code>Engine</code> cannot be
272      *   deallocated.
273      */
274     abstract protected void handleDeallocate() throws EngineException;
275
276     /** 
277      * Pauses the audio stream for this <code>Engine</code> and put
278      * this <code>Engine</code> into the <code>PAUSED</code> state.
279      *
280      * @throws EngineStateError if this <code>Engine</code> is in the
281      *   <code>DEALLOCATING_RESOURCES</code> or
282      *   <code>DEALLOCATED</code> state.
283      */
284     public void pause() throws EngineStateError {
285         synchronized (engineStateLock) {
286             checkEngineState(DEALLOCATED | DEALLOCATING_RESOURCES);
287             
288             if (testEngineState(PAUSED)) {
289                 return;
290             }
291             
292             handlePause();
293           
294             long[] states = setEngineState(RESUMED, PAUSED);
295             postEnginePaused(states[0], states[1]);
296         }
297     }
298
299     /**
300      * Called from the <code>pause</code> method.  Override this in subclasses.
301      */
302     abstract protected void handlePause();
303
304     /** 
305      * Resumes the audio stream for this <code>Engine</code> and put
306      * this <code>Engine</code> into the <code>RESUMED</code> state.
307      *
308      * @throws AudioException if unable to gain access to the audio channel
309      * @throws EngineStateError if this <code>Engine</code> is in the
310      *   <code>DEALLOCATING_RESOURCES</code> or
311      *   <code>DEALLOCATED</code> state
312      */
313     public void resume() throws AudioException, EngineStateError {
314         synchronized (engineStateLock) {
315             checkEngineState(DEALLOCATED | DEALLOCATING_RESOURCES);
316             
317             if (testEngineState(RESUMED))
318                 return;
319             
320             handleResume();
321             
322             long[] states = setEngineState(PAUSED, RESUMED);
323             postEngineResumed(states[0], states[1]);
324         }
325     }
326
327     /**
328      * Called from the <code>resume</code> method.  Override in subclasses.
329      */
330     abstract protected void handleResume();
331     
332     /**
333      * Returns an object that provides management of the audio input
334      * or output of this <code>Engine</code>.
335      *
336      * @return the audio manader for this <code>Engine</code>
337      */
338     public AudioManager getAudioManager() {
339         if (audioManager == null) {
340             audioManager = new BaseAudioManager();
341         }
342         return audioManager;
343     }
344
345     /**
346      * Returns an object that provides management of the vocabulary for
347      * this <code>Engine</code>.  Returns <code>null</code> if this
348      * <code>Engine</code> does not support vocabulary management.
349      *
350      * @return the vocabulary manager of this <code>Engine</code>
351      *
352      * @throws EngineStateError if this <code>Engine</code> in the
353      *   <code>DEALLOCATING_RESOURCES</code> or
354      *   <code>DEALLOCATED</code> state
355      */
356     public VocabManager getVocabManager() throws EngineStateError {
357         return null;
358     }
359
360     /**
361      * Gets the <code>EngineProperties</code> of this <code>Engine</code>.
362      * Must be set in subclasses.
363      *
364      * @return the <code>EngineProperties</code> of this <code>Engine</code>.
365      */
366     public EngineProperties getEngineProperties() {
367         return engineProperties;
368     }
369
370     /**
371      * Gets the current operating properties and mode of
372      * this <code>Engine</code>.
373      *
374      * @return the operating mode of this <code>Engine</code>
375      *
376      * @throws SecurityException
377      */
378     public EngineModeDesc getEngineModeDesc() throws SecurityException {
379         return engineModeDesc;
380     }
381
382     /**
383      * Sets the current operating properties and mode of
384      * this <code>Engine</code>.
385      *
386      * @param desc the new operating mode of this <code>Engine</code>
387      */
388     protected void setEngineModeDesc(EngineModeDesc desc) {
389         engineModeDesc = desc;
390     }
391
392     /**
393      * Requests notification of <code>EngineEvents</code> from this
394      * <code>Engine</code>.
395      *
396      * @param listener the listener to add.
397      */
398     public void addEngineListener(EngineListener listener) {
399         synchronized (engineListeners) {
400             if (!engineListeners.contains(listener)) {
401                 engineListeners.add(listener);
402             }
403         }
404     }
405
406     /**
407      * Removes an <code>EngineListener</code> from the list of
408      * <code>EngineListeners</code>.
409      *
410      * @param listener the listener to remove.
411      */
412     public void removeEngineListener(EngineListener listener) {
413         synchronized (engineListeners) {
414             engineListeners.remove(listener);
415         }
416     }
417     
418     /**
419      * Utility function that generates an
420      * <code>ENGINE_ALLOCATED</code> event and posts it
421      * to the event queue.  Eventually
422      * <code>fireEngineAllocated</code> will be called
423      * by the <code>dispatchSpeechEvent</code> as a result of this
424      * action.
425      *
426      * @param oldState the old state of this <code>Engine</code>
427      * @param newState the new state of this <code>Engine</code>
428      *
429      * @see #fireEngineAllocated
430      * @see #dispatchSpeechEvent
431      */
432     protected void postEngineAllocated(long oldState, long newState) {
433         SpeechEventUtilities.postSpeechEvent(
434             this,
435             new EngineEvent(
436                 this,
437                 EngineEvent.ENGINE_ALLOCATED,
438                 oldState, newState));
439     }
440     
441     /**
442      * Utility function that sends an <code>ENGINE_ALLOCATED</code>
443      * event to all <code>EngineListeners</code> registered with this
444      * <code>Engine</code>.  Called by <code>dispatchSpeechEvent</code>.
445      *
446      * @param event the <code>ENGINE_ALLOCATED</code> event
447      *
448      * @see #postEngineAllocated
449      * @see #dispatchSpeechEvent
450      */
451     public void fireEngineAllocated(EngineEvent event) {
452         if (engineListeners == null) {
453             return;
454         }
455         Iterator iterator = engineListeners.iterator();
456         while (iterator.hasNext()) {
457             EngineListener el = (EngineListener) iterator.next();
458             el.engineAllocated(event);
459         }
460     }
461     
462     /**
463      * Utility function that generates an
464      * <code>ENGINE_ALLOCATING_RESOURCES</code> event and
465      * posts it to the event queue.  Eventually
466      * <code>fireEngineAllocatingResources</code>
467      * will be called by <code>dispatchSpeechEvent</code> as a
468      * result of this action.
469      *
470      * @param oldState the old state of this <code>Engine</code>
471      * @param newState the new state of this <code>Engine</code>
472      *
473      * @see #fireEngineAllocatingResources
474      * @see #dispatchSpeechEvent
475      */
476     protected void postEngineAllocatingResources(long oldState,
477                                                  long newState) {
478         SpeechEventUtilities.postSpeechEvent(
479             this,
480             new EngineEvent(
481                 this,
482                 EngineEvent.ENGINE_ALLOCATING_RESOURCES,
483                 oldState, newState));
484     }
485     
486     /**
487      * Utility function that sends an
488      * <code>ENGINE_ALLOCATING_RESOURCES</code> event to all
489      * <code>EngineListeners</code> registered with this
490      * <code>Engine</code>.  Called by <code>dispatchSpeechEvent</code>.
491      *
492      * @param event the <code>ENGINE_ALLOCATING_RESOURCES</code> event
493      *
494      * @see #postEngineAllocatingResources
495      * @see #dispatchSpeechEvent
496      */
497     public void fireEngineAllocatingResources(EngineEvent event) {
498         if (engineListeners == null) {
499             return;
500         }
501         Iterator iterator = engineListeners.iterator();
502         while (iterator.hasNext()) {
503             EngineListener el = (EngineListener) iterator.next();
504             el.engineAllocatingResources(event);
505         }
506     }
507     
508     /**
509      * Utility function that generates an
510      * <code>ENGINE_DEALLOCATED</code> event and posts it
511      * to the event queue.  Eventually
512      * <code>fireEngineDeallocated</code> will be called
513      * by <code>dispatchSpeechEvent</code> as a result of this action.
514      *
515      * @param oldState the old state of this <code>Engine</code>
516      * @param newState the new state of this <code>Engine</code>
517      *
518      * @see #fireEngineDeallocated
519      * @see #dispatchSpeechEvent
520      */
521     protected void postEngineDeallocated(long oldState, long newState) {
522         SpeechEventUtilities.postSpeechEvent(
523             this,
524             new EngineEvent(
525                 this,
526                 EngineEvent.ENGINE_DEALLOCATED,
527                 oldState, newState));
528     }
529     
530     /**
531      * Utility function that sends an
532      * <code>ENGINE_DEALLOCATED</code> event to all
533      * <code>EngineListeners</code> registered with this
534      * <code>Engine</code>.  Called by <code>dispatchSpeechEvent</code>.
535      *
536      * @param event the <code>ENGINE_DEALLOCATED</code> event
537      *
538      * @see #postEngineDeallocated
539      * @see #dispatchSpeechEvent
540      */
541     public void fireEngineDeallocated(EngineEvent event) {
542         if (engineListeners == null) {
543             return;
544         }
545         Iterator iterator = engineListeners.iterator();
546         while (iterator.hasNext()) {
547             EngineListener el = (EngineListener) iterator.next();
548             el.engineDeallocated(event);
549         }
550     }
551     
552     /**
553      * Utility function that generates
554      * <code>ENGINE_DEALLOCATING_RESOURCES</code> event and
555      * posts it to the event queue.  Eventually
556      * <code>fireEngineAllocatingResources</code> will be called
557      * by <code>dispatchSpeechEvent</code> as a result of this action.
558      *
559      * @param oldState the old state of this <code>Engine</code>
560      * @param newState the new state of this <code>Engine</code>
561      *
562      * @see #fireEngineDeallocatingResources
563      * @see #dispatchSpeechEvent
564      */
565     protected void postEngineDeallocatingResources(long oldState,
566                                                    long newState) {
567         SpeechEventUtilities.postSpeechEvent(
568             this,
569             new EngineEvent(
570                 this,
571                 EngineEvent.ENGINE_DEALLOCATING_RESOURCES,
572                 oldState, newState));
573     }
574     
575     /**
576      * Utility function that sends a
577      * <code>ENGINE_DEALLOCATING_RESOURCES</code> event to all
578      * <code>EngineListeners</code> registered with this
579      * <code>Engine</code>.  Called by <code>dispatchSpeechEvent</code>.
580      *
581      * @param event the <code>ENGINE_DEALLOCATING_RESOURCES</code> event
582      *
583      * @see #postEngineDeallocatingResources
584      * @see #dispatchSpeechEvent
585      */
586     public void fireEngineDeallocatingResources(EngineEvent event) {
587         if (engineListeners == null) {
588             return;
589         }
590         Iterator iterator = engineListeners.iterator();
591         while (iterator.hasNext()) {
592             EngineListener el = (EngineListener) iterator.next();
593             el.engineDeallocatingResources(event);
594         }
595     }
596     
597     /**
598      * Utility function that generates an
599      * <code>ENGINE_PAUSED</code> event and posts it
600      * to the event queue.  Eventually
601      * <code>fireEnginePaused</code> will be called
602      * by <code>dispatchSpeechEvent</code> as a result of this action.
603      *
604      * @param oldState the old state of this <code>Engine</code>
605      * @param newState the new state of this <code>Engine</code>
606      *
607      * @see #fireEnginePaused
608      * @see #dispatchSpeechEvent
609      */
610     protected void postEnginePaused(long oldState, long newState) {
611         SpeechEventUtilities.postSpeechEvent(
612             this,
613             new EngineEvent(
614                 this,
615                 EngineEvent.ENGINE_PAUSED,
616                 oldState, newState));
617     }
618     
619     /**
620      * Utility function that sends an <code>ENGINE_PAUSED</code> event
621      * to all
622      * <code>EngineListeners</code> registered with this
623      * <code>Engine</code>.  Called by <code>dispatchSpeechEvent</code>.
624      *
625      * @param event the <code>ENGINE_PAUSED</code> event
626      *
627      * @see #postEnginePaused
628      * @see #dispatchSpeechEvent
629      */
630     public void fireEnginePaused(EngineEvent event) {
631         if (engineListeners == null) {
632             return;
633         }
634         Iterator iterator = engineListeners.iterator();
635         while (iterator.hasNext()) {
636             EngineListener el = (EngineListener) iterator.next();
637             el.enginePaused(event);
638         }
639     }
640
641     /**
642      * Utility function that generates an <code>ENGINE_RESUMED</code>
643      * event and posts it to the event queue.  Eventually
644      * <code>fireEngineResumed</code> will be called
645      * by <code>dispatchSpeechEvent</code> as a result of this action.
646      *
647      * @param oldState the old state of this <code>Engine</code>
648      * @param newState the new state of this <code>Engine</code>
649      *
650      * @see #fireEngineResumed
651      * @see #dispatchSpeechEvent
652      */
653     protected void postEngineResumed(long oldState, long newState) {
654         SpeechEventUtilities.postSpeechEvent(
655             this,
656             new EngineEvent(
657                 this,
658                 EngineEvent.ENGINE_RESUMED,
659                 oldState, newState));
660     }
661     
662     /**
663      * Utility function that sends an <code>ENGINE_RESUMED</code> event
664      * to all
665      * <code>EngineListeners</code> registered with this
666      * <code>Engine</code>.  Called by <code>dispatchSpeechEvent</code>.
667      *
668      * @param event the <code>ENGINE_RESUMED</code> event
669      *
670      * @see #postEngineResumed
671      * @see #dispatchSpeechEvent
672      */
673     public void fireEngineResumed(EngineEvent event) {
674         if (engineListeners == null) {
675             return;
676         }
677         Iterator iterator = engineListeners.iterator();
678         while (iterator.hasNext()) {
679             EngineListener el = (EngineListener) iterator.next();
680             el.engineResumed(event);
681         }
682     }
683
684     /**
685      * Factory constructor for EngineProperties object.
686      *
687      * @return a <code>BaseEngineProperties</code> object specific to
688      *   a subclass.
689      */
690     abstract protected BaseEngineProperties createEngineProperties();
691
692     /**
693      * Convenience method that throws an <code>EngineStateError</code>
694      * if any of the bits in the passed state are set in the
695      * <code>state</code>.
696      *
697      * @param state the <code>Engine</code> state to check
698      *
699      * @throws EngineStateError if any of the bits in the passed state
700      *   are set in the <code>state</code>
701      */
702     protected void checkEngineState(long state) throws EngineStateError {
703         long currentState = getEngineState();
704         if ((currentState & state) != 0) {
705             throw new EngineStateError
706                 ("Invalid EngineState: expected=(" 
707                  + stateToString(state) + ") current state=("
708                  + stateToString(currentState) + ")");
709         }
710     }
711
712     /**
713      * Returns a <code>String</code> of the names of all the
714      * <code>Engine</code> states in the given <code>Engine</code>
715      * state.
716      *
717      * @param state the bitmask of states
718      *
719      * @return a <code>String</code> containing the names of all the
720      *   states set in <code>state</code>
721      */
722     protected String stateToString(long state) {
723         StringBuffer buf = new StringBuffer();
724         if ((state & Engine.DEALLOCATED) != 0)
725             buf.append(" DEALLOCATED ");
726         if ((state & Engine.ALLOCATING_RESOURCES) != 0)
727             buf.append(" ALLOCATING_RESOURCES ");
728         if ((state & Engine.ALLOCATED) != 0)
729             buf.append(" ALLOCATED ");
730         if ((state & Engine.DEALLOCATING_RESOURCES) != 0)
731             buf.append(" DEALLOCATING_RESOURCES ");
732         if ((state & Engine.PAUSED) != 0)
733             buf.append(" PAUSED ");
734         if ((state & Engine.RESUMED) != 0)
735             buf.append(" RESUMED ");
736         return buf.toString();
737     }
738     
739     /**
740      * Dispatches a <code>SpeechEvent</code>.
741      * The dispatcher should notify all <code>EngineListeners</code>
742      * from this method.  The <code>SpeechEvent</code> was added
743      * via the various post methods of this class.
744      *
745      * @param event the <code>SpeechEvent</code> to dispatch
746      *
747      * @see #postEngineAllocatingResources
748      * @see #postEngineAllocated
749      * @see #postEngineDeallocatingResources
750      * @see #postEngineDeallocated
751      * @see #postEnginePaused
752      * @see #postEngineResumed
753      */
754     public void dispatchSpeechEvent(SpeechEvent event) {
755         switch (event.getId()) {
756             case EngineEvent.ENGINE_ALLOCATED:
757                 fireEngineAllocated((EngineEvent) event);
758                 break;
759             case EngineEvent.ENGINE_ALLOCATING_RESOURCES:
760                 fireEngineAllocatingResources((EngineEvent) event);
761                 break;
762             case EngineEvent.ENGINE_DEALLOCATED:
763                 fireEngineDeallocated((EngineEvent) event);
764                 break;
765             case EngineEvent.ENGINE_DEALLOCATING_RESOURCES:
766                 fireEngineDeallocatingResources((EngineEvent) event);
767                 break;
768             //case EngineEvent.ENGINE_ERROR:
769             //fireEngineError((EngineErrorEvent) event);
770             //break;
771             case EngineEvent.ENGINE_PAUSED:
772                 fireEnginePaused((EngineEvent) event);
773                 break;
774             case EngineEvent.ENGINE_RESUMED:
775                 fireEngineResumed((EngineEvent) event);
776                 break;
777         }
778     }
779
780     /**
781      * Returns the engine name and mode for debug purposes.
782      *
783      * @return the engine name and mode.
784      */
785     public String toString() {
786         return getEngineModeDesc().getEngineName() + 
787             ":" + getEngineModeDesc().getModeName();
788     }
789 }