blob: 8da48afcbdc8f09f0012f17f6bc6ac5a25b2ce3e [file] [log] [blame]
// Copyright 2017 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/speech/tts/tts_service_impl.h"
#include <lib/async/default.h>
#include <lib/fit/defer.h>
#include "src/speech/tts/tts_speaker.h"
#include "third_party/flite/include/flite_fuchsia.h"
namespace tts {
TtsServiceImpl::TtsServiceImpl(std::unique_ptr<sys::ComponentContext> startup_context)
: startup_context_(std::move(startup_context)) {
FX_DCHECK(startup_context_);
startup_context_->outgoing()->AddPublicService<fuchsia::tts::TtsService>(
[this](fidl::InterfaceRequest<fuchsia::tts::TtsService> request) {
clients_.insert(new Client(this, std::move(request)));
});
// Stash a pointer to our async_t.
dispatcher_ = async_get_default_dispatcher();
FX_DCHECK(dispatcher_);
}
TtsServiceImpl::~TtsServiceImpl() { FX_DCHECK(clients_.size() == 0); }
zx_status_t TtsServiceImpl::Init() {
int res = flite_init();
if (res < 0) {
FX_LOGS(ERROR) << "Failed to initialize flite (res " << res << ")";
return ZX_ERR_INTERNAL;
}
return ZX_OK;
}
TtsServiceImpl::Client::Client(TtsServiceImpl* owner, fidl::InterfaceRequest<TtsService> request)
: owner_(owner), binding_(this, std::move(request)) {
binding_.set_error_handler([this](zx_status_t status) { Shutdown(); });
}
TtsServiceImpl::Client::~Client() {
FX_DCHECK(active_speakers_.size() == 0);
FX_DCHECK(binding_.is_bound() == false);
}
void TtsServiceImpl::Client::Shutdown() {
for (const auto& speaker : active_speakers_) {
speaker->Shutdown();
}
binding_.Unbind();
active_speakers_.clear();
owner_->clients_.erase(owner_->clients_.find(this));
}
void TtsServiceImpl::Client::Say(std::string words, uint64_t token, SayCallback cbk) {
auto cleanup = fit::defer([this] { Shutdown(); });
auto speaker = std::make_shared<TtsSpeaker>(owner_->dispatcher_);
if (speaker->Init(owner_->startup_context_) != ZX_OK) {
return;
}
fit::closure on_speak_complete = [this, speaker, token, say_callback = std::move(cbk)]() mutable {
OnSpeakComplete(std::move(speaker), token, std::move(say_callback));
};
zx_status_t res = speaker->Speak(std::move(words), std::move(on_speak_complete));
if (res == ZX_OK) {
active_speakers_.insert(std::move(speaker));
} else {
FX_LOGS(ERROR) << "Failed to start to speak (res " << res << ")";
return;
}
cleanup.cancel();
}
void TtsServiceImpl::Client::OnSpeakComplete(const std::shared_ptr<TtsSpeaker>& speaker,
uint64_t token, SayCallback cbk) {
auto iter = active_speakers_.find(speaker);
if (iter == active_speakers_.end()) {
return;
}
speaker->Shutdown();
active_speakers_.erase(iter);
cbk(token);
}
} // namespace tts