Skip to content

Commit b3628fb

Browse files
authored
[flutter_tts] Refactor the C++ code (#401)
- Extract method. - Hiding tizen api in plugin.cc - Minimize use of output parameters - Change method name(Init-> TtsCreate, DeInit -> TtsDestroy, ...) - Change GetState() return type to use std::optional - int -> int32_t - remove debug log and [TTS] tag - rename callback functions - remove create and destroy function - etc + OnGetSpeechRateValidRange use android platform instead of tizen The value of "platform" is temporarily set to "android" instead of "tizen". Because it is not declared in TextToSpeechPlatform of TextToSpeech example.
1 parent da20d47 commit b3628fb

File tree

5 files changed

+292
-215
lines changed

5 files changed

+292
-215
lines changed

packages/flutter_tts/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## 1.2.1
2+
3+
* Refactor the C++ code.
4+
15
## 1.2.0
26

37
* Fix a bug where `setLanguage()` wasn't invoked due to typo in `setLanguage`.

packages/flutter_tts/pubspec.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ name: flutter_tts_tizen
22
description: The tizen implementation of flutter_tts plugin.
33
homepage: https://github.com/flutter-tizen/plugins
44
repository: https://github.com/flutter-tizen/plugins/tree/master/packages/flutter_tts
5-
version: 1.2.0
5+
version: 1.2.1
66

77
dependencies:
88
flutter:

packages/flutter_tts/tizen/src/flutter_tts_tizen_plugin.cc

Lines changed: 164 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,19 @@
88
#include <flutter/plugin_registrar.h>
99
#include <flutter/standard_method_codec.h>
1010

11-
#include <map>
1211
#include <memory>
13-
#include <sstream>
12+
#include <optional>
1413
#include <string>
1514
#include <vector>
1615

1716
#include "log.h"
1817
#include "text_to_speech.h"
1918

19+
namespace {
20+
21+
typedef flutter::MethodChannel<flutter::EncodableValue> FlMethodChannel;
22+
typedef flutter::MethodResult<flutter::EncodableValue> FlMethodResult;
23+
2024
class FlutterTtsTizenPlugin : public flutter::Plugin {
2125
public:
2226
static void RegisterWithRegistrar(flutter::PluginRegistrar *registrar) {
@@ -25,16 +29,23 @@ class FlutterTtsTizenPlugin : public flutter::Plugin {
2529
}
2630

2731
FlutterTtsTizenPlugin(flutter::PluginRegistrar *registrar) {
28-
channel_ =
29-
std::make_unique<flutter::MethodChannel<flutter::EncodableValue>>(
30-
registrar->messenger(), "flutter_tts",
31-
&flutter::StandardMethodCodec::GetInstance());
32+
channel_ = std::make_unique<FlMethodChannel>(
33+
registrar->messenger(), "flutter_tts",
34+
&flutter::StandardMethodCodec::GetInstance());
3235
channel_->SetMethodCallHandler([this](const auto &call, auto result) {
3336
this->HandleMethodCall(call, std::move(result));
3437
});
3538

3639
tts_ = std::make_unique<TextToSpeech>();
37-
tts_->SetOnStateChanagedCallback(
40+
if (!tts_->Initialize()) {
41+
// TODO : Handle initialization failure cases
42+
// Rarely, initializing TextToSpeech can fail. we should consider catching
43+
// the exception and propagating it to the flutter side. however, I think
44+
// this is optional because flutter side is not expecting any errors.
45+
tts_ = nullptr;
46+
return;
47+
}
48+
tts_->SetStateChanagedCallback(
3849
[this](tts_state_e previous, tts_state_e current) -> void {
3950
std::unique_ptr<flutter::EncodableValue> value =
4051
std::make_unique<flutter::EncodableValue>(true);
@@ -57,15 +68,14 @@ class FlutterTtsTizenPlugin : public flutter::Plugin {
5768
}
5869
});
5970

60-
tts_->SetOnUtteranceCompletedCallback([this](int utt_id) -> void {
61-
LOG_INFO("[TTS] Utterance (%d) is completed", utt_id);
71+
tts_->SetUtteranceCompletedCallback([this](int32_t utt_id) -> void {
6272
std::unique_ptr<flutter::EncodableValue> args =
6373
std::make_unique<flutter::EncodableValue>(true);
6474
channel_->InvokeMethod("speak.onComplete", std::move(args));
6575
HandleAwaitSpeakCompletion(1);
6676
});
6777

68-
tts_->SetErrorCallback([](int utt_id, tts_error_e reason) -> void {
78+
tts_->SetErrorCallback([](int32_t utt_id, tts_error_e reason) -> void {
6979
// It seems unnecessary for now.
7080
});
7181
}
@@ -82,121 +92,175 @@ class FlutterTtsTizenPlugin : public flutter::Plugin {
8292
// notify the dart code of any method call failures from the host platform.
8393
// However, in the case of flutter_tts, it expects a return value 0 on
8494
// failure(and value 1 on success). Therefore in the scope of this plugin,
85-
// we call result->Success(flutter::EncodableValue(0)) to notify errors.
86-
95+
// we call SendResult(flutter::EncodableValue(0)); to notify errors.
8796
const auto method_name = method_call.method_name();
8897
const auto &arguments = *method_call.arguments();
8998

90-
if (method_name.compare("awaitSpeakCompletion") == 0) {
91-
if (std::holds_alternative<bool>(arguments)) {
92-
await_speak_completion_ = std::get<bool>(arguments);
93-
result->Success(flutter::EncodableValue(1));
94-
return;
95-
}
96-
result->Success(flutter::EncodableValue(0));
97-
} else if (method_name.compare("speak") == 0) {
98-
if (tts_->GetState() == TTS_STATE_PLAYING) {
99-
LOG_ERROR("[TTS] : You cannot speak again while speaking.");
100-
result->Success(flutter::EncodableValue(0));
101-
return;
102-
}
99+
result_ = std::move(result);
103100

104-
if (std::holds_alternative<std::string>(arguments)) {
105-
std::string text = std::get<std::string>(arguments);
106-
if (!tts_->AddText(text)) {
107-
result->Success(flutter::EncodableValue(0));
108-
return;
109-
}
110-
}
101+
if (!tts_) {
102+
result_->Error("Operation failed", "TTS is invalid.");
103+
return;
104+
}
111105

112-
if (tts_->Speak()) {
113-
if (await_speak_completion_ && !result_for_await_speak_completion_) {
114-
LOG_DEBUG("Store result ptr for await speak completion");
115-
result_for_await_speak_completion_ = std::move(result);
116-
} else {
117-
result->Success(flutter::EncodableValue(1));
118-
}
119-
} else {
120-
result->Success(flutter::EncodableValue(0));
106+
if (method_name == "awaitSpeakCompletion") {
107+
OnAwaitSpeakCompletion(arguments);
108+
} else if (method_name == "speak") {
109+
OnSpeak(arguments);
110+
} else if (method_name == "stop") {
111+
OnStop();
112+
} else if (method_name == "pause") {
113+
OnPause();
114+
} else if (method_name == "getSpeechRateValidRange") {
115+
OnGetSpeechRateValidRange();
116+
} else if (method_name == "setSpeechRate") {
117+
OnSetSpeechRate(arguments);
118+
} else if (method_name == "setLanguage") {
119+
OnSetLanguage(arguments);
120+
} else if (method_name == "getLanguages") {
121+
OnGetLanguage();
122+
} else if (method_name == "setVolume") {
123+
OnSetVolume(arguments);
124+
} else {
125+
result_->NotImplemented();
126+
}
127+
}
128+
129+
void OnAwaitSpeakCompletion(const flutter::EncodableValue &arguments) {
130+
if (std::holds_alternative<bool>(arguments)) {
131+
await_speak_completion_ = std::get<bool>(arguments);
132+
SendResult(flutter::EncodableValue(1));
133+
return;
134+
}
135+
SendResult(flutter::EncodableValue(0));
136+
}
137+
138+
void OnSpeak(const flutter::EncodableValue &arguments) {
139+
std::optional<TtsState> state = tts_->GetState();
140+
if (!state.has_value() || state == TtsState::kPlaying) {
141+
if (state.has_value() && state == TtsState::kPlaying) {
142+
LOG_ERROR("You cannot speak again while speaking.");
121143
}
122-
} else if (method_name.compare("stop") == 0) {
123-
if (tts_->Stop()) {
124-
result->Success(flutter::EncodableValue(1));
125-
} else {
126-
result->Success(flutter::EncodableValue(0));
144+
SendResult(flutter::EncodableValue(0));
145+
return;
146+
}
147+
148+
if (std::holds_alternative<std::string>(arguments)) {
149+
std::string text = std::get<std::string>(arguments);
150+
if (!tts_->AddText(text)) {
151+
SendResult(flutter::EncodableValue(0));
152+
return;
127153
}
128-
} else if (method_name.compare("pause") == 0) {
129-
if (tts_->Pause()) {
130-
result->Success(flutter::EncodableValue(1));
154+
}
155+
156+
if (tts_->Speak()) {
157+
if (await_speak_completion_ && !result_for_await_speak_completion_) {
158+
result_for_await_speak_completion_ = std::move(result_);
131159
} else {
132-
result->Success(flutter::EncodableValue(0));
133-
}
134-
} else if (method_name.compare("getSpeechRateValidRange") == 0) {
135-
int min = 0, normal = 0, max = 0;
136-
tts_->GetSpeedRange(&min, &normal, &max);
137-
flutter::EncodableMap map;
138-
map.insert(std::pair<flutter::EncodableValue, flutter::EncodableValue>(
139-
"min", min));
140-
map.insert(std::pair<flutter::EncodableValue, flutter::EncodableValue>(
141-
"normal", normal));
142-
map.insert(std::pair<flutter::EncodableValue, flutter::EncodableValue>(
143-
"max", max));
144-
map.insert(std::pair<flutter::EncodableValue, flutter::EncodableValue>(
145-
"platform", "tizen"));
146-
result->Success(flutter::EncodableValue(std::move(map)));
147-
} else if (method_name.compare("setSpeechRate") == 0) {
148-
if (std::holds_alternative<double>(arguments)) {
149-
int speed = (int)std::get<double>(arguments);
150-
tts_->SetTtsSpeed(speed);
151-
result->Success(flutter::EncodableValue(1));
152-
return;
160+
SendResult(flutter::EncodableValue(1));
153161
}
154-
result->Success(flutter::EncodableValue(0));
155-
} else if (method_name.compare("setLanguage") == 0) {
156-
if (std::holds_alternative<std::string>(arguments)) {
157-
std::string language = std::move(std::get<std::string>(arguments));
158-
tts_->SetDefaultLanguage(language);
159-
result->Success(flutter::EncodableValue(1));
162+
} else {
163+
SendResult(flutter::EncodableValue(0));
164+
}
165+
}
166+
167+
void OnStop() {
168+
if (tts_->Stop()) {
169+
SendResult(flutter::EncodableValue(1));
170+
} else {
171+
SendResult(flutter::EncodableValue(0));
172+
}
173+
}
174+
175+
void OnPause() {
176+
if (tts_->Pause()) {
177+
SendResult(flutter::EncodableValue(1));
178+
} else {
179+
SendResult(flutter::EncodableValue(0));
180+
}
181+
}
182+
183+
void OnGetSpeechRateValidRange() {
184+
int32_t min = 0, normal = 0, max = 0;
185+
tts_->GetSpeedRange(&min, &normal, &max);
186+
// FIXME: The value of "platform" is temporarily set to "android" instead of
187+
// "tizen". Because it is not declared in TextToSpeechPlatform of
188+
// TextToSpeech example.
189+
flutter::EncodableMap map = {
190+
{flutter::EncodableValue("min"), flutter::EncodableValue(min)},
191+
{flutter::EncodableValue("normal"), flutter::EncodableValue(normal)},
192+
{flutter::EncodableValue("max"), flutter::EncodableValue(max)},
193+
{flutter::EncodableValue("platform"),
194+
flutter::EncodableValue("android")},
195+
};
196+
SendResult(flutter::EncodableValue(map));
197+
}
198+
199+
void OnSetSpeechRate(const flutter::EncodableValue &arguments) {
200+
if (std::holds_alternative<double>(arguments)) {
201+
int32_t speed = std::get<double>(arguments);
202+
tts_->SetTtsSpeed(speed);
203+
SendResult(flutter::EncodableValue(1));
204+
return;
205+
}
206+
SendResult(flutter::EncodableValue(0));
207+
}
208+
209+
void OnSetLanguage(const flutter::EncodableValue &arguments) {
210+
if (std::holds_alternative<std::string>(arguments)) {
211+
std::string language = std::move(std::get<std::string>(arguments));
212+
tts_->SetDefaultLanguage(language);
213+
SendResult(flutter::EncodableValue(1));
214+
return;
215+
}
216+
SendResult(flutter::EncodableValue(0));
217+
}
218+
219+
void OnGetLanguage() {
220+
flutter::EncodableList list;
221+
for (auto language : tts_->GetSupportedLanaguages()) {
222+
list.push_back(flutter::EncodableValue(language));
223+
}
224+
SendResult(flutter::EncodableValue(list));
225+
}
226+
227+
void OnSetVolume(const flutter::EncodableValue &arguments) {
228+
if (std::holds_alternative<double>(arguments)) {
229+
double volume = std::get<double>(arguments);
230+
if (tts_->SetVolume(volume)) {
231+
SendResult(flutter::EncodableValue(1));
160232
return;
161233
}
162-
result->Success(flutter::EncodableValue(0));
163-
} else if (method_name.compare("getLanguages") == 0) {
164-
flutter::EncodableList list;
165-
for (auto language : tts_->GetSupportedLanaguages()) {
166-
list.push_back(flutter::EncodableValue(language));
167-
}
168-
result->Success(flutter::EncodableValue(list));
169-
} else if (method_name.compare("setVolume") == 0) {
170-
if (std::holds_alternative<double>(arguments)) {
171-
double rate = std::get<double>(arguments);
172-
if (tts_->SetVolume(rate)) {
173-
result->Success(flutter::EncodableValue(1));
174-
return;
175-
}
176-
}
177-
result->Success(flutter::EncodableValue(0));
178-
} else {
179-
result->Error("-1", "Not supported method");
180234
}
235+
SendResult(flutter::EncodableValue(0));
236+
}
237+
238+
void SendResult(const flutter::EncodableValue &result) {
239+
if (!result_) {
240+
return;
241+
}
242+
result_->Success(result);
243+
result_ = nullptr;
181244
}
182245

183-
void HandleAwaitSpeakCompletion(int value) {
246+
void HandleAwaitSpeakCompletion(int32_t value) {
184247
if (await_speak_completion_) {
185-
LOG_DEBUG("Send result for await speak completion[%d]", value);
186248
result_for_await_speak_completion_->Success(
187249
flutter::EncodableValue(value));
188250
result_for_await_speak_completion_ = nullptr;
189251
}
190252
}
191253

192254
std::unique_ptr<TextToSpeech> tts_;
193-
std::unique_ptr<flutter::MethodChannel<flutter::EncodableValue>> channel_;
194-
195255
bool await_speak_completion_ = false;
196-
std::unique_ptr<flutter::MethodResult<flutter::EncodableValue>>
197-
result_for_await_speak_completion_;
256+
257+
std::unique_ptr<FlMethodResult> result_for_await_speak_completion_;
258+
std::unique_ptr<FlMethodResult> result_;
259+
std::unique_ptr<FlMethodChannel> channel_;
198260
};
199261

262+
} // namespace
263+
200264
void FlutterTtsTizenPluginRegisterWithRegistrar(
201265
FlutterDesktopPluginRegistrarRef registrar) {
202266
FlutterTtsTizenPlugin::RegisterWithRegistrar(

0 commit comments

Comments
 (0)