After an evaluation, GNOME has moved from Bugzilla to GitLab. Learn more about GitLab.
No new issues can be reported in GNOME Bugzilla anymore.
To report an issue in a GNOME project, go to GNOME GitLab.
Do not go to GNOME Gitlab for: Bluefish, Doxygen, GnuCash, GStreamer, java-gnome, LDTP, NetworkManager, Tomboy.
Bug 535493 - eSpeak driver 'say' method can block
eSpeak driver 'say' method can block
Status: RESOLVED FIXED
Product: gnome-speech
Classification: Deprecated
Component: drivers
unspecified
Other All
: Normal major
: ---
Assigned To: Willie Walker
GNOME Speech Maintainer(s)
Depends on:
Blocks: 529784
 
 
Reported: 2008-05-29 13:49 UTC by Willie Walker
Modified: 2008-07-08 19:13 UTC
See Also:
GNOME target: ---
GNOME version: ---


Attachments
Patch to use a speech queue for espeak-synthesis-driver (9.85 KB, patch)
2008-06-11 20:00 UTC, Willie Walker
committed Details | Review

Description Willie Walker 2008-05-29 13:49:56 UTC
Test case:

1) run gnome-speech's test-speech application
2) Choose the eSpeak server/driver
3) Select 'm' for gender
4) Select 'all' to display all voices

The test-speech application quickly lists about 27 voices and then pauses for each one thereafter.  What should happen is that the test-speech should quickly list all the voices without pause. 

The immediate problem seems to be in the gnome-speech driver for eSpeak.  In particular, espeaksynthesisdriver.c:espeak_synthesis_driver_say has a while(1) loop in it that looks like the following (the printf lines and the else clause were added by me for debugging):

   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)
     {
           printf("OK\n");
       break;
     }
       else {
         printf("BUFFER FULL!!!!\n");
       }
       usleep(20000);
     };

The effect of this loop is that it causes the 'say' command to block until the eSpeak buffer frees enough to let the espeak_Synth command work.  Instead, the 'say' command should never block and should be asynchronous.

There are a couple of approaches we could take here: 1) modify gnome-speech to queue things up rather than doing a while/sleep loop in 'say' or 2) increase eSpeak's buffer size to lower the likelihood of the buffer getting full.

Modifying the gnome-speech driver for eSpeak might be the best option from a technical standpoint, but it might be complex to implement.  The DECtalk synthesis driver, however, seems to do this by processing synthesis operations in a gidle handler.  It could possibly be used as a model.

Modifying eSpeak itself would be rather simple (bump eSpeak's fifo.cpp:MAX_NODE_COUNTER value up), but would really just be a bandaid.
Comment 1 Kenny Hitt 2008-05-30 18:47:27 UTC
I tried changing the value of MAX_NODE_COUNTER from 200 to 2000 in espeak's fifo.cpp file with no luck.  It looks like changing gnome-speech will probably be the only solution.
I'm currently looking at gnome-speech code in an attempt to make the suggested fix.
(In reply to comment #0)
> Test case:
> 
> 1) run gnome-speech's test-speech application
> 2) Choose the eSpeak server/driver
> 3) Select 'm' for gender
> 4) Select 'all' to display all voices
> 
> The test-speech application quickly lists about 27 voices and then pauses for
> each one thereafter.  What should happen is that the test-speech should quickly
> list all the voices without pause. 
> 
> The immediate problem seems to be in the gnome-speech driver for eSpeak.  In
> particular, espeaksynthesisdriver.c:espeak_synthesis_driver_say has a while(1)
> loop in it that looks like the following (the printf lines and the else clause
> were added by me for debugging):
> 
>    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)
>      {
>            printf("OK\n");
>        break;
>      }
>        else {
>          printf("BUFFER FULL!!!!\n");
>        }
>        usleep(20000);
>      };
> 
> The effect of this loop is that it causes the 'say' command to block until the
> eSpeak buffer frees enough to let the espeak_Synth command work.  Instead, the
> 'say' command should never block and should be asynchronous.
> 
> There are a couple of approaches we could take here: 1) modify gnome-speech to
> queue things up rather than doing a while/sleep loop in 'say' or 2) increase
> eSpeak's buffer size to lower the likelihood of the buffer getting full.
> 
> Modifying the gnome-speech driver for eSpeak might be the best option from a
> technical standpoint, but it might be complex to implement.  The DECtalk
> synthesis driver, however, seems to do this by processing synthesis operations
> in a gidle handler.  It could possibly be used as a model.
> 
> Modifying eSpeak itself would be rather simple (bump eSpeak's
> fifo.cpp:MAX_NODE_COUNTER value up), but would really just be a bandaid.
> 

Comment 2 Willie Walker 2008-06-05 19:06:45 UTC
(In reply to comment #1)
> I'm currently looking at gnome-speech code in an attempt to make the suggested
> fix.

Thanks Kenny!  Please let me know how work progresses here.  This is something I'd like to see fixed for GNOME 2.22.3 if it can be done.  :-)
Comment 3 Willie Walker 2008-06-11 20:00:45 UTC
Created attachment 112573 [details] [review]
Patch to use a speech queue for espeak-synthesis-driver

Here's a patch that enqueues calls to say and handles them on the gidle thread.  Seems to work OK for me and I'm not seeing the blocked calls any longer.

Kenny can you give this a shot?
Comment 4 Willie Walker 2008-06-16 17:10:14 UTC
Committed for 0.4.20.