8
8
#include < flutter/plugin_registrar.h>
9
9
#include < flutter/standard_method_codec.h>
10
10
11
- #include < map>
12
11
#include < memory>
13
- #include < sstream >
12
+ #include < optional >
14
13
#include < string>
15
14
#include < vector>
16
15
17
16
#include " log.h"
18
17
#include " text_to_speech.h"
19
18
19
+ namespace {
20
+
21
+ typedef flutter::MethodChannel<flutter::EncodableValue> FlMethodChannel;
22
+ typedef flutter::MethodResult<flutter::EncodableValue> FlMethodResult;
23
+
20
24
class FlutterTtsTizenPlugin : public flutter ::Plugin {
21
25
public:
22
26
static void RegisterWithRegistrar (flutter::PluginRegistrar *registrar) {
@@ -25,16 +29,23 @@ class FlutterTtsTizenPlugin : public flutter::Plugin {
25
29
}
26
30
27
31
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 ());
32
35
channel_->SetMethodCallHandler ([this ](const auto &call, auto result) {
33
36
this ->HandleMethodCall (call, std::move (result));
34
37
});
35
38
36
39
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 (
38
49
[this ](tts_state_e previous, tts_state_e current) -> void {
39
50
std::unique_ptr<flutter::EncodableValue> value =
40
51
std::make_unique<flutter::EncodableValue>(true );
@@ -57,15 +68,14 @@ class FlutterTtsTizenPlugin : public flutter::Plugin {
57
68
}
58
69
});
59
70
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 {
62
72
std::unique_ptr<flutter::EncodableValue> args =
63
73
std::make_unique<flutter::EncodableValue>(true );
64
74
channel_->InvokeMethod (" speak.onComplete" , std::move (args));
65
75
HandleAwaitSpeakCompletion (1 );
66
76
});
67
77
68
- tts_->SetErrorCallback ([](int utt_id, tts_error_e reason) -> void {
78
+ tts_->SetErrorCallback ([](int32_t utt_id, tts_error_e reason) -> void {
69
79
// It seems unnecessary for now.
70
80
});
71
81
}
@@ -82,121 +92,175 @@ class FlutterTtsTizenPlugin : public flutter::Plugin {
82
92
// notify the dart code of any method call failures from the host platform.
83
93
// However, in the case of flutter_tts, it expects a return value 0 on
84
94
// 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.
87
96
const auto method_name = method_call.method_name ();
88
97
const auto &arguments = *method_call.arguments ();
89
98
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);
103
100
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
+ }
111
105
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." );
121
143
}
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 ;
127
153
}
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_);
131
159
} 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 ));
153
161
}
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 ));
160
232
return ;
161
233
}
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" );
180
234
}
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 ;
181
244
}
182
245
183
- void HandleAwaitSpeakCompletion (int value) {
246
+ void HandleAwaitSpeakCompletion (int32_t value) {
184
247
if (await_speak_completion_) {
185
- LOG_DEBUG (" Send result for await speak completion[%d]" , value);
186
248
result_for_await_speak_completion_->Success (
187
249
flutter::EncodableValue (value));
188
250
result_for_await_speak_completion_ = nullptr ;
189
251
}
190
252
}
191
253
192
254
std::unique_ptr<TextToSpeech> tts_;
193
- std::unique_ptr<flutter::MethodChannel<flutter::EncodableValue>> channel_;
194
-
195
255
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_;
198
260
};
199
261
262
+ } // namespace
263
+
200
264
void FlutterTtsTizenPluginRegisterWithRegistrar (
201
265
FlutterDesktopPluginRegistrarRef registrar) {
202
266
FlutterTtsTizenPlugin::RegisterWithRegistrar (
0 commit comments