Implement audio device control

This commit is contained in:
Kovid Goyal 2023-01-29 19:25:28 +05:30
parent 20de91c75e
commit 8939c81399
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
2 changed files with 55 additions and 9 deletions

View File

@ -665,6 +665,19 @@ handle_save(id_type cmd_id, std::vector<std::wstring_view> &parts) {
typedef std::function<void(id_type, std::vector<std::wstring_view>, int64_t*)> handler_function;
static DeviceInformationKind
get_device_kind(const std::wstring x) {
if (x == L"device") return DeviceInformationKind::Device;
if (x == L"association_endpoint") return DeviceInformationKind::AssociationEndpoint;
if (x == L"association_endpoint_container") return DeviceInformationKind::AssociationEndpointContainer;
if (x == L"association_endpoint_service") return DeviceInformationKind::AssociationEndpointService;
if (x == L"device_container") return DeviceInformationKind::DeviceContainer;
if (x == L"device_interface") return DeviceInformationKind::DeviceInterface;
if (x == L"device_interface_class") return DeviceInformationKind::DeviceInterfaceClass;
if (x == L"device_panel") return DeviceInformationKind::DevicePanel;
return DeviceInformationKind::Unknown;
}
static const std::unordered_map<std::string, handler_function> handlers = {
{"exit", [](id_type cmd_id, std::vector<std::wstring_view> parts, int64_t* exit_code) {
@ -689,7 +702,9 @@ static const std::unordered_map<std::string, handler_function> handlers = {
}},
{"state", [](id_type cmd_id, std::vector<std::wstring_view> parts, int64_t*) {
output(cmd_id, "state", {{"playback_state", media_player.PlaybackSession().PlaybackState()}});
auto ps = media_player.PlaybackSession();
if (ps) output(cmd_id, "state", {{"playback_state", ps.PlaybackState()}});
else output(cmd_id, "state", {{"playback_state", ""}});
}},
{"default_voice", [](id_type cmd_id, std::vector<std::wstring_view> parts, int64_t*) {
@ -709,17 +724,26 @@ static const std::unordered_map<std::string, handler_function> handlers = {
}},
{"audio_device", [](id_type cmd_id, std::vector<std::wstring_view> parts, int64_t*) {
bool found = false;
if (parts.size()) {
auto di = DeviceInformation::CreateFromIdAsync(parts[0]).get();
media_player.AudioDevice(di);
auto device_kind = std::wstring(parts.at(0));
parts.erase(parts.begin(), parts.begin() + 1);
auto device_id = join(parts);
auto di = DeviceInformation::CreateFromIdAsync(device_id, {}, get_device_kind(device_kind)).get();
if (di) {
media_player.AudioDevice(di);
found = true;
}
}
output(cmd_id, "audio_device", {{"value", media_player.AudioDevice()}});
auto x = media_player.AudioDevice();
if (x) output(cmd_id, "audio_device", {{"value", x}, {"found", found}});
else output(cmd_id, "audio_device", {{"value", ""}, {"found", found}});
}},
{"voice", [](id_type cmd_id, std::vector<std::wstring_view> parts, int64_t*) {
bool found = false;
if (parts.size()) {
auto voice_id = winrt::hstring(parts[0]);
auto voice_id = winrt::hstring(parts.at(0));
for (auto const &candidate : SpeechSynthesizer::AllVoices()) {
if (candidate.Id() == voice_id) {
speech_synthesizer.Voice(candidate);
@ -728,12 +752,14 @@ static const std::unordered_map<std::string, handler_function> handlers = {
}
}
}
output(cmd_id, "voice", {{"value", speech_synthesizer.Voice()}, {"found", found}});
auto x = speech_synthesizer.Voice();
if (x) output(cmd_id, "voice", {{"value", speech_synthesizer.Voice()}, {"found", found}});
else output(cmd_id, "voice", {{"value", ""}, {"found", found}});
}},
{"volume", [](id_type cmd_id, std::vector<std::wstring_view> parts, int64_t*) {
if (parts.size()) {
auto vol = parse_double(parts[0].data());
auto vol = parse_double(parts.at(0).data());
if (vol < 0 || vol > 1) throw std::out_of_range("Invalid volume value must be between 0 and 1");
speech_synthesizer.Options().AudioVolume(vol);
}
@ -742,7 +768,7 @@ static const std::unordered_map<std::string, handler_function> handlers = {
{"rate", [](id_type cmd_id, std::vector<std::wstring_view> parts, int64_t*) {
if (parts.size()) {
auto rate = parse_double(parts[0].data());
auto rate = parse_double(parts.at(0).data());
if (rate < 0.5 || rate > 6.0) throw std::out_of_range("Invalid rate value must be between 0.5 and 6");
speech_synthesizer.Options().SpeakingRate(rate);
}
@ -751,7 +777,7 @@ static const std::unordered_map<std::string, handler_function> handlers = {
{"pitch", [](id_type cmd_id, std::vector<std::wstring_view> parts, int64_t*) {
if (parts.size()) {
auto pitch = parse_double(parts[0].data());
auto pitch = parse_double(parts.at(0).data());
if (pitch < 0 || pitch > 2) throw std::out_of_range("Invalid pitch value must be between 0 and 2");
speech_synthesizer.Options().AudioPitch(pitch);
}

View File

@ -133,3 +133,23 @@ def develop_save(text='Lucca Brazzi sleeps with the fishes.', filename="speech.w
with SharedMemory(size=max_buffer_size(text)) as shm:
sz = encode_to_file_object(text, shm)
develop_loop(f'2 save {st} {sz} {shm.name} {filename}', 2)
def develop_interactive():
import subprocess
from calibre.debug import run_calibre_debug
print('\x1b[32mInteractive winspeech', '\x1b[39m]]'[:-2], flush=True)
p = run_calibre_debug('-c', 'from calibre_extensions.winspeech import run_main_loop; raise SystemExit(run_main_loop())',
stdin=subprocess.PIPE)
try:
while True:
line = input()
if p.poll() is not None:
raise SystemExit(p.returncode)
p.stdin.write((line + '\n').encode())
p.stdin.flush()
except KeyboardInterrupt:
print('Exiting on interrupt', flush=True)
finally:
if p.poll() is None:
p.kill()