https://github.com/espeak-ng/espeak-ng/issues/172

Upstream pcaudiolib made audio_object_flush actually do the
close/reopen, but this is not released yet (will be in 1.1). This
however poses threading issues with ALSA: audio_object_flush is
currently called in the application thread while it must be done in
the say_thread for proper safety.

espeak-ng 1.49.2 added a cancel_audio() function which calls
audio_object_flush and is called from close_stream(). That is however
not enough for the stream to get interrupted on cancel (and we don't
want to use upstream's current fix mentioned above since it poses
threading issues).

---
 src/libespeak-ng/fifo.c   |    4 ++++
 src/libespeak-ng/speech.c |   23 +++++++++++++++++++++++
 src/libespeak-ng/speech.h |    3 +++
 3 files changed, 30 insertions(+)

--- a/src/libespeak-ng/fifo.c
+++ b/src/libespeak-ng/fifo.c
@@ -358,6 +358,10 @@ static void *say_thread(void *p)
 		}
 
 		if (my_stop_is_required || my_terminate_is_required) {
+			// restart the audio early, to be more responsive when using eSpeak NG
+			// for audio.
+			close_audio();
+			open_audio();
 			// no mutex required since the stop command is synchronous
 			// and waiting for my_cond_stop_is_acknowledged
 			init(1);
--- a/src/libespeak-ng/speech.c
+++ b/src/libespeak-ng/speech.c
@@ -97,6 +97,28 @@ void cancel_audio(void)
 #endif
 }
 
+void close_audio(void)
+{
+#ifdef HAVE_PCAUDIOLIB_AUDIO_H
+	if ((my_mode & ENOUTPUT_MODE_SPEAK_AUDIO) == ENOUTPUT_MODE_SPEAK_AUDIO) {
+		audio_object_close(my_audio);
+	}
+#endif
+}
+
+void open_audio(void)
+{
+#ifdef HAVE_PCAUDIOLIB_AUDIO_H
+	if ((my_mode & ENOUTPUT_MODE_SPEAK_AUDIO) == ENOUTPUT_MODE_SPEAK_AUDIO) {
+		int error = audio_object_open(my_audio, AUDIO_OBJECT_FORMAT_S16LE, voice_samplerate, 1);
+		if (error != 0) {
+			fprintf(stderr, "error: %s\n", audio_object_strerror(my_audio, error));
+			err = ENS_AUDIO_ERROR;
+		}
+	}
+#endif
+}
+
 static int dispatch_audio(short *outbuf, int length, espeak_EVENT *event)
 {
 	int a_wave_can_be_played = 1;
@@ -571,6 +593,7 @@ espeak_ng_STATUS sync_espeak_Synth(unsig
 	espeak_ng_STATUS aStatus = Synthesize(unique_identifier, text, flags);
 #if USE_LIBPCAUDIO
 	if ((my_mode & ENOUTPUT_MODE_SPEAK_AUDIO) == ENOUTPUT_MODE_SPEAK_AUDIO) {
+	    /* FIXME: This drain poses cancelling problems for end of speechs */
 		int error = (aStatus == ENS_SPEECH_STOPPED)
 		          ? audio_object_flush(my_audio)
 		          : audio_object_drain(my_audio);
--- a/src/libespeak-ng/speech.h
+++ b/src/libespeak-ng/speech.h
@@ -80,6 +80,9 @@ extern "C"
 
 void cancel_audio(void);
 
+void close_audio(void);
+void open_audio(void);
+
 extern char path_home[N_PATH_HOME];    // this is the espeak-ng-data directory
 
 #ifdef __cplusplus
