Index: drivers/espeak/espeaksynthesisdriver.c
===================================================================
--- drivers/espeak/espeaksynthesisdriver.c	(revision 311)
+++ drivers/espeak/espeaksynthesisdriver.c	(working copy)
@@ -1,7 +1,7 @@
 /*
  * GNOME Speech - Speech services for the GNOME desktop
  *
- * Copyright 2007 Sun Microsystems Inc.
+ * Copyright 2007-2008 Sun Microsystems Inc.
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public
@@ -27,20 +27,28 @@
 #include <string.h>
 #include <stdlib.h>
 #include <libbonobo.h>
+#include <glib.h>
 #include <glib/gmain.h>
 #include <speak_lib.h>
 #include <gnome-speech/gnome-speech.h>
 #include "espeaksynthesisdriver.h"
 #include "espeakspeaker.h"
  
-
 #define VERSION_LENGTH 20
 
+static gint utterance_id = 0;
+
 typedef struct {
   GNOME_Speech_SpeechCallback cb;
   gboolean speech_is_started;
-} t_index;
+  gint id;
+} t_user_data;
 
+typedef struct {
+  EspeakSpeaker *espeak_speaker;
+  char *text;
+  t_user_data *user_data;
+} t_utterance;
 
 static GObjectClass *parent_class;
 
@@ -51,13 +59,6 @@
 }
 
 
-static gboolean
-espeak_synthesis_driver_timeout_callback (void *data)
-{
-  return TRUE;
-}
-
-
 static int
 espeak_synthesis_driver_index_callback (short* wav,
 					int numsamples,
@@ -65,8 +66,9 @@
 {
   if (event && event->user_data)
     {
-      t_index *user_data = event->user_data;
-      GNOME_Speech_speech_callback_type type=GNOME_Speech_speech_callback_speech_started;
+      t_user_data *user_data = event->user_data;
+      GNOME_Speech_speech_callback_type type = 
+        GNOME_Speech_speech_callback_speech_started;
       
       gboolean a_callback_is_called = TRUE;
 
@@ -102,7 +104,7 @@
 	  CORBA_exception_init (&ev);
 	  GNOME_Speech_SpeechCallback_notify (user_data->cb,
 					      type,
-					      event->unique_identifier,
+					      user_data->id,
 					      event->text_position,
 					      &ev);
 
@@ -174,11 +176,7 @@
     espeak_Initialize(AUDIO_OUTPUT_PLAYBACK, 200, NULL);
 #endif
 
-    /* Add a timeout callback to poke this instance of eSpeak */
-
-    d->timeout_id = g_timeout_add_full (G_PRIORITY_HIGH_IDLE, 100,
-					espeak_synthesis_driver_timeout_callback, d, NULL);
-		
+    d->text_idle = 0;
     d->initialized = TRUE;
   }
   return d->initialized;
@@ -383,13 +381,38 @@
 {
   driver->mutex = g_mutex_new ();
   driver->last_speaker = NULL;
-  driver->index_queue = NULL;
-  driver->timeout_id = -1;
+  driver->utterance_queue = NULL;
 }
 
 
+static void
+espeak_synthesis_driver_free_utterance (t_utterance *utterance)
+{
+  g_free (utterance->text);
+  g_free (utterance);
+}
 
+
 static void
+espeak_synthesis_driver_flush_queue (EspeakSynthesisDriver *driver)
+{
+  GSList *tmp;
+	
+  /* Flush the utterance queue */
+
+  g_mutex_lock (driver->mutex);
+  for (tmp = driver->utterance_queue; tmp; tmp = tmp->next) {
+    t_utterance *u = (t_utterance *) tmp->data;
+    espeak_synthesis_driver_free_utterance (u);
+  }
+  g_slist_free (driver->utterance_queue);
+  driver->utterance_queue = NULL;
+  g_mutex_unlock (driver->mutex);
+}
+
+
+
+static void
 espeak_synthesis_driver_finalize (GObject *obj)
 {
   EspeakSynthesisDriver *d = ESPEAK_SYNTHESIS_DRIVER (obj);
@@ -397,10 +420,10 @@
   espeak_Synchronize ();
   espeak_Terminate ();
 
-  /* Remove timeout */
+  if (d->text_idle)
+    g_source_remove (d->text_idle);
 
-  if (d->timeout_id >= 0)
-    g_source_remove (d->timeout_id);
+  espeak_synthesis_driver_flush_queue (d);
 
   if (parent_class->finalize)
     parent_class->finalize (obj);
@@ -487,59 +510,104 @@
 }
 
 
+
+static gboolean
+espeak_idle(gpointer data)
+{
+  EspeakSynthesisDriver *driver = ESPEAK_SYNTHESIS_DRIVER (data);
+  gboolean rerun;
+
+  g_mutex_lock (driver->mutex);
+
+  if (driver->utterance_queue) {
+    t_utterance *utterance;
+    unsigned int unique_identifier=0;
+    espeak_ERROR a_error = EE_INTERNAL_ERROR;
+
+    utterance = (t_utterance *) driver->utterance_queue->data;
+    espeak_SetVoiceByProperties(&utterance->espeak_speaker->voice);      
+    a_error = espeak_Synth((char *) utterance->text, 
+			   strlen((char*)utterance->text) + 1, 
+			   0, POS_CHARACTER, 0, espeakCHARS_UTF8,
+			   &unique_identifier, 
+			   utterance->user_data);
+
+    if (a_error != EE_BUFFER_FULL) {
+      driver->utterance_queue = g_slist_remove_link (
+        driver->utterance_queue,
+	driver->utterance_queue);
+      espeak_synthesis_driver_free_utterance (utterance);
+    }
+  }
+
+  if (driver->utterance_queue) {
+    rerun = TRUE;
+  } else {
+    driver->text_idle = 0;
+    rerun = FALSE;
+  }
+  
+  g_mutex_unlock (driver->mutex);
+
+  return rerun;
+}
+
+
 gint
-espeak_synthesis_driver_say (EspeakSynthesisDriver *d,
-			     EspeakSpeaker *s,
+espeak_synthesis_driver_say (EspeakSynthesisDriver *driver,
+			     EspeakSpeaker *espeak_speaker,
 			     gchar *text)
 {
-  Speaker *speaker = SPEAKER (s);
-  espeak_ERROR a_error = EE_INTERNAL_ERROR;
-  gint a_status = -1;
-  unsigned int unique_identifier=0;
-	
-  /* If this speaker wasn't the last one to speak, reset the speech parameters */
+  t_utterance *utterance = NULL;
+  Speaker *speaker = SPEAKER (espeak_speaker);
 
-  if (d->last_speaker != s || speaker_needs_parameter_refresh(speaker)) {
+  speaker = SPEAKER (espeak_speaker);
+  if (driver->last_speaker != espeak_speaker 
+      || speaker_needs_parameter_refresh(speaker)) {
     speaker_refresh_parameters (speaker);
-    d->last_speaker = s;
+    driver->last_speaker = espeak_speaker;
   }
-	
-  t_index *user_data = NULL;
 
-  if (speaker->cb != CORBA_OBJECT_NIL) 
-  {
+  utterance = g_new (t_utterance, 1);
+  utterance->espeak_speaker = espeak_speaker;
+  utterance->text = g_strdup (text);
+
+  if (speaker->cb != CORBA_OBJECT_NIL) {
+    t_user_data *user_data;
     CORBA_Environment ev;
-
-    user_data = g_new(t_index, 1);
+    user_data = g_new(t_user_data, 1);
     CORBA_exception_init (&ev);
     user_data->cb = CORBA_Object_duplicate (speaker->cb, &ev);
+    CORBA_exception_free (&ev);
     user_data->speech_is_started = FALSE;
-    CORBA_exception_free (&ev);
+    user_data->id = ++utterance_id;
+    utterance->user_data = user_data;
+  } else {
+    utterance->user_data = NULL;
   }
 
-  while(1)
-    {
-      a_error = espeak_Synth((char *) text, strlen((char*)text)+1, 
-			     0, POS_CHARACTER, 0, espeakCHARS_UTF8,
-			     &unique_identifier, user_data);
-      if (a_error != EE_BUFFER_FULL)
-	{
-	  break;
-	}
-      usleep(20000);
-    };
+  g_mutex_lock (driver->mutex);
+  driver->utterance_queue = g_slist_append (driver->utterance_queue, 
+					    utterance);
+  if (!driver->text_idle) {
+      driver->text_idle = g_idle_add (espeak_idle, driver);
+  }
+  g_mutex_unlock (driver->mutex);
 
-
-  if (a_error == EE_OK)
-      a_status = (gint)unique_identifier;
-
-  return a_status;
+  return utterance_id;
 }
 
 
 gboolean
 espeak_synthesis_driver_stop (EspeakSynthesisDriver *d)
 {
+  if (d->text_idle) {
+    g_source_remove (d->text_idle);
+    d->text_idle = 0;
+  }
+
+  espeak_synthesis_driver_flush_queue (d);
+
   espeak_Cancel ();
   return TRUE;
 }
Index: drivers/espeak/espeakspeaker.c
===================================================================
--- drivers/espeak/espeakspeaker.c	(revision 311)
+++ drivers/espeak/espeakspeaker.c	(working copy)
@@ -1,7 +1,7 @@
 /*
  * GNOME Speech - Speech services for the GNOME desktop
  *
- * Copyright 2007 Sun Microsystems Inc.
+ * Copyright 2007-2008 Sun Microsystems Inc.
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public
@@ -267,12 +267,11 @@
   s->driver = g_object_ref (d);
 
   /* Set the specified voice */
-  espeak_VOICE a_voice;
-  memset( &a_voice, 0, sizeof(espeak_VOICE));
-  a_voice.name = voice_spec->name;
-  a_voice.languages = NULL;
-  a_voice.gender = (voice_spec->gender == GNOME_Speech_gender_male);
-  espeak_SetVoiceByProperties(&a_voice);      
+  memset( &speaker->voice, 0, sizeof(espeak_VOICE));
+  speaker->voice.name = g_strdup(voice_spec->name);
+  speaker->voice.languages = NULL;
+  speaker->voice.gender = (voice_spec->gender == GNOME_Speech_gender_male);
+  espeak_SetVoiceByProperties(&speaker->voice);      
 
   espeak_add_parameter (speaker,
 			espeakPITCH,
@@ -290,7 +289,7 @@
 			espeakRATE,
 			"rate",
 			80,
-			370,
+			390,
 			espeak_set_rate);  
   espeak_add_parameter (speaker,
 			espeakVOLUME,
Index: drivers/espeak/espeaksynthesisdriver.h
===================================================================
--- drivers/espeak/espeaksynthesisdriver.h	(revision 311)
+++ drivers/espeak/espeaksynthesisdriver.h	(working copy)
@@ -1,7 +1,7 @@
 /*
  * GNOME Speech - Speech services for the GNOME desktop
  *
- * Copyright 2007 Sun Microsystems Inc.
+ * Copyright 2007-2008 Sun Microsystems Inc.
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public
@@ -50,7 +50,8 @@
 
 	EspeakSpeaker *last_speaker;
 	guint timeout_id;
-	GSList *index_queue;
+	guint text_idle;
+	GSList *utterance_queue;
 	gboolean initialized;
 } EspeakSynthesisDriver;
 
Index: drivers/espeak/espeakspeaker.h
===================================================================
--- drivers/espeak/espeakspeaker.h	(revision 311)
+++ drivers/espeak/espeakspeaker.h	(working copy)
@@ -1,7 +1,7 @@
 /*
  * GNOME Speech - Speech services for the GNOME desktop
  *
- * Copyright 2007 Sun Microsystems Inc.
+ * Copyright 2007-2008 Sun Microsystems Inc.
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public
@@ -49,6 +49,7 @@
 
 typedef struct {
 	Speaker parent;
+        espeak_VOICE voice;
 } EspeakSpeaker;
 
 typedef struct {
@@ -60,7 +61,7 @@
 
 EspeakSpeaker *
 espeak_speaker_new (GObject *d,
-		      const GNOME_Speech_VoiceInfo *voice_speec);
+		      const GNOME_Speech_VoiceInfo *voice_spec);
 
 #ifdef __cplusplus
 }
