Repository: MycroftAI/mycroft-core

Issue:
wait_while_speaking() it does not work
I have been having problems with "wait_while_speaking ()" for a while. even on multiple devices. i use espeak as tts. Even if I attach wait = True to speak_dialog there is no waiting and I have to incorporate a time delay into my skills. i import "from mycroft.audio import wait_while_speaking"


Discussion:
Thanks for reporting, I compared mimic and espeak and for espeak I can reproduce this issue so there's defintely something that's going wrong there. espeak is not using the newer tts architecture so I'll might try to update it to the more modern version and see if things improve.

Resolving patch:
diff --git a/mycroft/tts/espeak_tts.py b/mycroft/tts/espeak_tts.py
--- a/mycroft/tts/espeak_tts.py
+++ b/mycroft/tts/espeak_tts.py
@@ -18,14 +18,23 @@
 
 
 class ESpeak(TTS):
+    """TTS module for generating speech using ESpeak."""
     def __init__(self, lang, config):
         super(ESpeak, self).__init__(lang, config, ESpeakValidator(self))
 
-    def execute(self, sentence, ident=None, listen=False):
-        self.begin_audio()
-        subprocess.call(
-            ['espeak', '-v', self.lang + '+' + self.voice, sentence])
-        self.end_audio(listen)
+    def get_tts(self, sentence, wav_file):
+        """Generate WAV from sentence, phonemes aren't supported.
+
+        Arguments:
+            sentence (str): sentence to generate audio for
+            wav_file (str): output file
+
+        Returns:
+            tuple ((str) file location, None)
+        """
+        subprocess.call(['espeak', '-v', self.lang + '+' + self.voice,
+                         '-w', wav_file, sentence])
+        return wav_file, None
 
 
 class ESpeakValidator(TTSValidator):
@@ -40,8 +49,8 @@ def validate_connection(self):
         try:
             subprocess.call(['espeak', '--version'])
         except Exception:
-            raise Exception(
-                'ESpeak is not installed. Run: sudo apt-get install espeak')
+            raise Exception('ESpeak is not installed. Please install it on '
+                            'your system and restart Mycroft.')
 
     def get_tts_class(self):
         return ESpeak
diff --git a/mycroft/tts/tts.py b/mycroft/tts/tts.py
--- a/mycroft/tts/tts.py
+++ b/mycroft/tts/tts.py
@@ -187,7 +187,7 @@ def __init__(self, lang, config, validator, audio_ext='wav',
 
     def load_spellings(self):
         """Load phonetic spellings of words as dictionary"""
-        path = join('text', self.lang, 'phonetic_spellings.txt')
+        path = join('text', self.lang.lower(), 'phonetic_spellings.txt')
         spellings_file = resolve_resource_file(path)
         if not spellings_file:
             return {}


Test patch:
diff --git a/test/unittests/tts/test_espeak_tts.py b/test/unittests/tts/test_espeak_tts.py
new file mode 100644
--- /dev/null
+++ b/test/unittests/tts/test_espeak_tts.py
@@ -0,0 +1,23 @@
+import unittest
+from unittest import mock
+
+from mycroft.tts.espeak_tts import ESpeak
+
+
+@mock.patch('mycroft.tts.tts.PlaybackThread')
+class TestMimic(unittest.TestCase):
+    @mock.patch('mycroft.tts.espeak_tts.subprocess')
+    def test_get_tts(self, mock_subprocess, _):
+        conf = {
+            "lang": "english-us",
+            "voice": "m1"
+        }
+        e = ESpeak('en-US', conf)
+        sentence = 'hello'
+        wav_filename = 'abc.wav'
+        wav, phonemes = e.get_tts(sentence, wav_filename)
+        self.assertTrue(phonemes is None)
+        mock_subprocess.call.called_with(['espeak', '-v',
+                                          conf['lang'] + '+' + conf['voice'],
+                                          '-w', wav_filename,
+                                          sentence])
diff --git a/test/unittests/tts/test_mimic_tts.py b/test/unittests/tts/test_mimic_tts.py
--- a/test/unittests/tts/test_mimic_tts.py
+++ b/test/unittests/tts/test_mimic_tts.py
@@ -23,9 +23,9 @@ def test_get_tts(self, mock_subprocess, _, mock_device_api):
         mock_device_api.return_value = device_instance_mock
         m = Mimic('en-US', {})
         wav, phonemes = m.get_tts('hello', 'abc.wav')
+        mock_subprocess.check_output.assert_called_once_with(
+            m.args + ['-o', 'abc.wav', '-t', 'hello'])
         self.assertEqual(phonemes, mock_subprocess.check_output().decode())
-        mock_subprocess.check_output_called_with(m.args + ['-o', 'abc.wav',
-                                                           '-t', 'hello'])
 
     def test_viseme(self, _, mock_device_api):
         mock_device_api.return_value = device_instance_mock
diff --git a/test/unittests/tts/test_tts.py b/test/unittests/tts/test_tts.py
--- a/test/unittests/tts/test_tts.py
+++ b/test/unittests/tts/test_tts.py
@@ -120,7 +120,6 @@ def test_phoneme_cache(self, mock_open, _):
             self.assertEqual(read_phonemes, 'phonemes')  # assert stripped
 
     def test_ssml_support(self, _):
-
         sentence = "<speak>Prosody can be used to change the way words " \
                    "sound. The following words are " \
                    "<prosody volume='x-loud'> " \
@@ -175,6 +174,16 @@ def test_ssml_support(self, _):
         self.assertEqual(mycroft.tts.TTS.remove_ssml(sentence),
                          sentence_no_ssml)
 
+    def test_load_spellings(self, _):
+        """Check that the spelling dictionary gets loaded."""
+        tts = MockTTS("en-US", {}, MockTTSValidator(None))
+        self.assertTrue(tts.spellings != {})
+
+    def test_load_spelling_missing(self, _):
+        """Test that a missing phonetic spelling dictionary counts as empty."""
+        tts = MockTTS("as-DF", {}, MockTTSValidator(None))
+        self.assertTrue(tts.spellings == {})
+
 
 class TestTTSFactory(unittest.TestCase):
     @mock.patch('mycroft.tts.tts.Configuration')