diff --git a/src/calibre/utils/windows/winspeech.cpp b/src/calibre/utils/windows/winspeech.cpp index d51392d6c4..b75d23bfa8 100644 --- a/src/calibre/utils/windows/winspeech.cpp +++ b/src/calibre/utils/windows/winspeech.cpp @@ -205,20 +205,24 @@ public: return serialize_string_for_json(s, out); case DT_LIST: { out << '['; + bool first = true; for (auto const &i : list) { + if (!first) out << ", "; + first = false; i.serialize(out); - out << ", "; } out << ']'; break; } case DT_OBJECT: { out << '{'; + bool first = true; for (const auto& [key, value]: object) { + if (!first) out << ", "; + first = false; serialize_string_for_json(key, out); out << ": "; value.serialize(out); - out << ", "; } out << '}'; break; diff --git a/src/calibre/utils/windows/winspeech.py b/src/calibre/utils/windows/winspeech.py index b2d66ffe86..6a29a217c4 100644 --- a/src/calibre/utils/windows/winspeech.py +++ b/src/calibre/utils/windows/winspeech.py @@ -2,22 +2,34 @@ # License: GPLv3 Copyright: 2023, Kovid Goyal +import json import sys import time from contextlib import closing +from queue import Queue from threading import Thread from calibre.utils.ipc.simple_worker import start_pipe_worker +def decode_msg(line: bytes) -> dict: + parts = line.strip().split(b' ', 2) + msg_id, msg_type, ans = int(parts[0]), parts[1].decode(), json.loads(parts[2]) + ans['related_to'] = msg_id + ans['payload_type'] = msg_type + return ans + + def develop_speech(text='Lucca brazzi sleeps with the fishes'): p = start_pipe_worker('from calibre_extensions.winspeech import run_main_loop; run_main_loop()') - print('\x1b[32mSpeaking', text, '\x1b[39m', flush=True) + print('\x1b[32mSpeaking', text, '\x1b[39m', flush=True) # ]] + q = Queue() def echo_output(p): for line in p.stdout: - sys.stdout.buffer.write(b'\x1b[33m' + line + b'\x1b[39m') + sys.stdout.buffer.write(b'\x1b[33m' + line + b'\x1b[39m') # ]] sys.stdout.buffer.flush() + q.put(decode_msg(line)) def send(*a): cmd = ' '.join(map(str, a)) + '\n' @@ -29,10 +41,13 @@ def develop_speech(text='Lucca brazzi sleeps with the fishes'): try: send('1 echo Synthesizer started') send('2 speak text inline', text) - time.sleep(6) + while True: + m = q.get() + if m['payload_type'] == 'media_state_changed' and m['state'] == 'ended': + break send('3 echo Synthesizer exiting') send('exit') - time.sleep(1) + p.wait(1) finally: if p.poll() is None: p.kill()