Skip to content

Commit

Permalink
Resolve PlaybackThread-related errors (#180)
Browse files Browse the repository at this point in the history
# Description
Refactor to prevent duplicated `PlaybackThread` instances
Patch out ovos_utils/ovos_workshop deprecation warnings that affect
versions currently incompatible with this package
Refactor to implement upstream `synth` method and drop internal
`_get_tts` method

# Issues
- Refactoring on `ovos_audio` possibly closes #140

# Other Notes
Resolves observed Mark2 issues where `wait_while_speaking` sometimes
times out without a response from the Audio service
  • Loading branch information
NeonDaniel authored Feb 12, 2025
1 parent 07b81b5 commit 282c304
Show file tree
Hide file tree
Showing 4 changed files with 26 additions and 13 deletions.
6 changes: 6 additions & 0 deletions neon_audio/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,9 @@
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

# Patching deprecation warnings
# TODO: Deprecate after migration to ovos-workshop 1.0+ requirement
import ovos_workshop.resource_files
from ovos_utils.bracket_expansion import expand_template
ovos_workshop.resource_files.expand_options = expand_template
11 changes: 5 additions & 6 deletions neon_audio/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,20 +80,19 @@ def __init__(self, ready_hook=on_ready, error_hook=on_error,
:param bus: Connected MessageBusClient
:param disable_ocp: if True, disable OVOS Common Play service
"""
from neon_utils.signal_utils import create_signal
# Patch import so PlaybackService creates a `NeonPlaybackThread` object
from neon_audio.tts.neon import NeonPlaybackThread
ovos_audio.service.PlaybackThread = NeonPlaybackThread

if audio_config:
LOG.info("Updating global config with passed config")
from neon_audio.utils import patch_config
patch_config(audio_config)
bus = bus or get_messagebus()
from neon_utils.signal_utils import create_signal

PlaybackService.__init__(self, ready_hook, error_hook, stopping_hook,
alive_hook, started_hook, watchdog, bus,
disable_ocp, validate_source=False)
del self.playback_thread
from neon_audio.tts.neon import NeonPlaybackThread
from ovos_plugin_manager.tts import TTS
self.playback_thread = NeonPlaybackThread(TTS.queue, self.bus)
LOG.debug(f'Initialized tts={self._tts_hash} | '
f'fallback={self._fallback_tts_hash}')
create_signal("neon_speak_api") # Create signal so skills use API
Expand Down
21 changes: 14 additions & 7 deletions neon_audio/tts/neon.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@

from os.path import dirname
from time import time
from typing import List

from json_database import JsonStorageXDG
from ovos_bus_client.apis.enclosure import EnclosureAPI
Expand All @@ -50,7 +51,7 @@
from ovos_config.config import Configuration


def get_requested_tts_languages(msg) -> list:
def get_requested_tts_languages(msg) -> List[dict]:
"""
Builds a list of the requested TTS for a given spoken response
:param msg: Message associated with request
Expand Down Expand Up @@ -152,7 +153,7 @@ def _sort_timing_metrics(timings: dict) -> dict:

class NeonPlaybackThread(PlaybackThread):
def __init__(self, queue, bus=None):
LOG.info("Initializing NeonPlaybackThread")
LOG.info(f"Initializing NeonPlaybackThread with queue={queue}")
PlaybackThread.__init__(self, queue, bus=bus)

def begin_audio(self, message: Message = None):
Expand All @@ -172,7 +173,7 @@ def end_audio(self, listen, message=None):
check_for_signal("isSpeaking")

def _play(self):
LOG.debug(f"Start playing {self._now_playing}")
LOG.debug(f"Start playing {self._now_playing} from queue={self.queue}")
# wav_file, vis, listen, ident, message
ident = self._now_playing[3]
message = self._now_playing[4]
Expand Down Expand Up @@ -260,7 +261,11 @@ def _init_playback(self, playback_thread: NeonPlaybackThread = None):
return
TTS.playback.shutdown()
if not isinstance(playback_thread, NeonPlaybackThread):
LOG.exception("Received invalid playback_thread")
LOG.exception(f"Received invalid playback_thread: {playback_thread}")
if isinstance(playback_thread, PlaybackThread):
LOG.warning(f"Joining {playback_thread}")
playback_thread.stop()
playback_thread.join()
playback_thread = None
init_signal_bus(self.bus)
TTS.playback = playback_thread or NeonPlaybackThread(TTS.queue)
Expand All @@ -276,7 +281,8 @@ def _init_playback(self, playback_thread: NeonPlaybackThread = None):
LOG.exception("Error starting the playback thread")

def _get_tts(self, sentence: str, request: dict = None, **kwargs):
# TODO: Signature should be made to match ovos-audio
log_deprecation("This method is deprecated without replacement",
"1.6.0")
if any([x in inspect.signature(self.get_tts).parameters
for x in {"speaker", "wav_file"}]):
LOG.info(f"Legacy Neon TTS signature found ({self.__class__.__name__})")
Expand Down Expand Up @@ -332,8 +338,9 @@ def get_multiple_tts(self, message, **kwargs) -> dict:
LOG.info(f"Got translated sentence: {tx_sentence}")
else:
tx_sentence = sentence
wav_file, phonemes = self._get_tts(tx_sentence, request, **kwargs)

kwargs['speaker'] = request
audio_obj, phonemes = self.synth(tx_sentence, **kwargs)
wav_file = str(audio_obj)
# If this is the first response, populate translation and phonemes
responses.setdefault(tts_lang, {"sentence": tx_sentence,
"translated": tx_sentence != sentence,
Expand Down
1 change: 1 addition & 0 deletions tests/unit_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,7 @@ def test_validator_invalid(self):
tts.shutdown()

def test_get_tts(self):
# TODO: Deprecate
test_file_path = join(dirname(__file__), "test.wav")
file, phonemes = self.tts._get_tts("test", wav_file=test_file_path,
speaker={})
Expand Down

0 comments on commit 282c304

Please sign in to comment.