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>
14
12
#include < string>
15
13
#include < vector>
16
14
17
15
#include " log.h"
18
16
#include " text_to_speech.h"
19
17
18
+ namespace {
19
+
20
+ typedef flutter::MethodChannel<flutter::EncodableValue> FlMethodChannel;
21
+ typedef flutter::MethodResult<flutter::EncodableValue> FlMethodResult;
22
+
20
23
class FlutterTtsTizenPlugin : public flutter ::Plugin {
21
24
public:
22
25
static void RegisterWithRegistrar (flutter::PluginRegistrar *registrar) {
@@ -25,15 +28,25 @@ class FlutterTtsTizenPlugin : public flutter::Plugin {
25
28
}
26
29
27
30
FlutterTtsTizenPlugin (flutter::PluginRegistrar *registrar) {
28
- channel_ =
29
- std::make_unique<flutter::MethodChannel<flutter::EncodableValue>>(
30
- registrar->messenger (), " flutter_tts" ,
31
- &flutter::StandardMethodCodec::GetInstance ());
31
+ channel_ = std::make_unique<FlMethodChannel>(
32
+ registrar->messenger (), " flutter_tts" ,
33
+ &flutter::StandardMethodCodec::GetInstance ());
32
34
channel_->SetMethodCallHandler ([this ](const auto &call, auto result) {
33
35
this ->HandleMethodCall (call, std::move (result));
34
36
});
35
37
36
38
tts_ = std::make_unique<TextToSpeech>();
39
+ try {
40
+ tts_->Initialize ();
41
+ } catch (const TextToSpeechError &error) {
42
+ // TODO : Handle initialization failure cases
43
+ // Rarely, initializing TextToSpeech can fail. we should consider catching
44
+ // the exception and propagating it to the flutter side. however, I think
45
+ // this is optional because flutter side is not expecting any errors.
46
+ LOG_ERROR (" Operation failed : %s" , error.GetErrorString ().c_str ());
47
+ tts_ = nullptr ;
48
+ return ;
49
+ }
37
50
tts_->SetOnStateChanagedCallback (
38
51
[this ](tts_state_e previous, tts_state_e current) -> void {
39
52
std::unique_ptr<flutter::EncodableValue> value =
@@ -76,108 +89,177 @@ class FlutterTtsTizenPlugin : public flutter::Plugin {
76
89
void HandleMethodCall (
77
90
const flutter::MethodCall<flutter::EncodableValue> &method_call,
78
91
std::unique_ptr<flutter::MethodResult<flutter::EncodableValue>> result) {
79
- // Keep in sync with the return values implemented in:
80
- // https://github.com/dlutton/flutter_tts/blob/master/android/src/main/java/com/tundralabs/fluttertts/FlutterTtsPlugin.java.
81
- // In principle, MethodResult was designed to call MethodResult.Error() to
82
- // notify the dart code of any method call failures from the host platform.
83
- // However, in the case of flutter_tts, it expects a return value 0 on
84
- // 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
-
87
92
const auto method_name = method_call.method_name ();
88
93
const auto &arguments = *method_call.arguments ();
89
94
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 ));
95
+ result_ = std::move (result);
96
+
97
+ if (!tts_) {
98
+ result_->Error (" Operation failed" , " TTS is invalid." );
99
+ return ;
100
+ }
101
+
102
+ if (method_name == " awaitSpeakCompletion" ) {
103
+ OnAwaitSpeakCompletion (arguments);
104
+ } else if (method_name == " speak" ) {
105
+ OnSpeak (arguments);
106
+ } else if (method_name == " stop" ) {
107
+ OnStop ();
108
+ } else if (method_name == " pause" ) {
109
+ OnPause ();
110
+ } else if (method_name == " getSpeechRateValidRange" ) {
111
+ OnGetSpeechRateValidRange ();
112
+ } else if (method_name == " setSpeechRate" ) {
113
+ OnSetSpeechRate (arguments);
114
+ } else if (method_name == " setLanguage" ) {
115
+ OnSetLanguage (arguments);
116
+ } else if (method_name == " getLanguages" ) {
117
+ OnGetLanguage ();
118
+ } else if (method_name == " setVolume" ) {
119
+ OnSetVolume (arguments);
120
+ } else {
121
+ result_->NotImplemented ();
122
+ }
123
+ }
124
+
125
+ void OnAwaitSpeakCompletion (const flutter::EncodableValue &arguments) {
126
+ if (std::holds_alternative<bool >(arguments)) {
127
+ await_speak_completion_ = std::get<bool >(arguments);
128
+ SendResult (flutter::EncodableValue (1 ));
129
+ return ;
130
+ }
131
+ SendErrorResult (" Invalid argument" , " Argument is invaild." );
132
+ }
133
+
134
+ void OnSpeak (const flutter::EncodableValue &arguments) {
135
+ try {
136
+ if (tts_->GetState () == TtsState::kPlaying ) {
137
+ SendErrorResult (" Operation cancelled" ,
138
+ " You cannot speak again while speaking." );
101
139
return ;
102
140
}
103
141
104
142
if (std::holds_alternative<std::string>(arguments)) {
105
143
std::string text = std::get<std::string>(arguments);
106
- if (!tts_->AddText (text)) {
107
- result->Success (flutter::EncodableValue (0 ));
108
- return ;
109
- }
144
+ tts_->AddText (text);
110
145
}
111
146
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 ));
121
- }
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 ));
127
- }
128
- } else if (method_name.compare (" pause" ) == 0 ) {
129
- if (tts_->Pause ()) {
130
- result->Success (flutter::EncodableValue (1 ));
131
- } else {
132
- result->Success (flutter::EncodableValue (0 ));
133
- }
134
- } else if (method_name.compare (" getSpeechRateValidRange" ) == 0 ) {
135
- int min = 0 , normal = 0 , max = 0 ;
147
+ tts_->Speak ();
148
+
149
+ } catch (const TextToSpeechError &error) {
150
+ SendErrorResult (" Operation failed" , error.GetErrorString ());
151
+ }
152
+
153
+ if (await_speak_completion_ && !result_for_await_speak_completion_) {
154
+ LOG_DEBUG (" Store result ptr for await speak completion" );
155
+ result_for_await_speak_completion_ = std::move (result_);
156
+ } else {
157
+ SendResult (flutter::EncodableValue (1 ));
158
+ }
159
+ }
160
+
161
+ void OnStop () {
162
+ try {
163
+ tts_->Stop ();
164
+ } catch (const TextToSpeechError &error) {
165
+ SendErrorResult (" Operation failed" , error.GetErrorString ());
166
+ }
167
+ SendResult (flutter::EncodableValue (1 ));
168
+ }
169
+
170
+ void OnPause () {
171
+ try {
172
+ tts_->Pause ();
173
+ } catch (const TextToSpeechError &error) {
174
+ SendErrorResult (" Operation failed" , error.GetErrorString ());
175
+ }
176
+ SendResult (flutter::EncodableValue (1 ));
177
+ }
178
+
179
+ void OnGetSpeechRateValidRange () {
180
+ int min = 0 , normal = 0 , max = 0 ;
181
+ try {
136
182
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 ;
153
- }
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 ));
183
+ } catch (const TextToSpeechError &error) {
184
+ SendErrorResult (" Operation failed" , error.GetErrorString ());
185
+ return ;
186
+ }
187
+ flutter::EncodableMap map;
188
+ map.insert (std::pair<flutter::EncodableValue, flutter::EncodableValue>(
189
+ " min" , min));
190
+ map.insert (std::pair<flutter::EncodableValue, flutter::EncodableValue>(
191
+ " normal" , normal ));
192
+ map.insert (std::pair<flutter::EncodableValue, flutter::EncodableValue>(
193
+ " max" , max));
194
+ map.insert (std::pair<flutter::EncodableValue, flutter::EncodableValue>(
195
+ " platform" , " tizen" ));
196
+ SendResult (flutter::EncodableValue (std::move (map)));
197
+ }
198
+
199
+ void OnSetSpeechRate (const flutter::EncodableValue &arguments) {
200
+ if (std::holds_alternative<double >(arguments)) {
201
+ int speed = (int )std::get<double >(arguments);
202
+ tts_->SetTtsSpeed (speed);
203
+ SendResult (flutter::EncodableValue (1 ));
204
+ return ;
205
+ }
206
+ SendErrorResult (" Invalid argument" , " SpeechRate is invaild." );
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
+ SendErrorResult (" Invalid argument" , " Language is invaild." );
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
+ try {
231
+ tts_->SetVolume (volume);
232
+ } catch (const TextToSpeechError &error) {
233
+ SendErrorResult (" Operation failed" , error.GetErrorString ());
160
234
return ;
161
235
}
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
236
}
237
+ SendErrorResult (" Invalid argument" , " Volume is invaild." );
238
+ }
239
+
240
+ void SendResult (const flutter::EncodableValue &result) {
241
+ if (!result_) {
242
+ return ;
243
+ }
244
+ result_->Success (result);
245
+ result_ = nullptr ;
246
+ }
247
+
248
+ void SendErrorResult (const std::string &error_code,
249
+ const std::string &error_message) {
250
+ // Keep in sync with the return values implemented in:
251
+ // https://github.com/dlutton/flutter_tts/blob/master/android/src/main/java/com/tundralabs/fluttertts/FlutterTtsPlugin.java.
252
+ // In principle, MethodResult was designed to call MethodResult.Error() to
253
+ // notify the dart code of any method call failures from the host platform.
254
+ // However, in the case of flutter_tts, it expects a return value 0 on
255
+ // failure(and value 1 on success). Therefore in the scope of this plugin,
256
+ // we call result_->Success(flutter::EncodableValue(0)) to notify errors.
257
+ if (!result_) {
258
+ return ;
259
+ }
260
+ LOG_ERROR (" %s" , std::string (error_code + " : " + error_message).c_str ());
261
+ result_->Success (flutter::EncodableValue (0 ));
262
+ result_ = nullptr ;
181
263
}
182
264
183
265
void HandleAwaitSpeakCompletion (int value) {
@@ -190,13 +272,15 @@ class FlutterTtsTizenPlugin : public flutter::Plugin {
190
272
}
191
273
192
274
std::unique_ptr<TextToSpeech> tts_;
193
- std::unique_ptr<flutter::MethodChannel<flutter::EncodableValue>> channel_;
194
-
195
275
bool await_speak_completion_ = false ;
196
- std::unique_ptr<flutter::MethodResult<flutter::EncodableValue>>
197
- result_for_await_speak_completion_;
276
+
277
+ std::unique_ptr<FlMethodResult> result_for_await_speak_completion_;
278
+ std::unique_ptr<FlMethodResult> result_;
279
+ std::unique_ptr<FlMethodChannel> channel_;
198
280
};
199
281
282
+ } // namespace
283
+
200
284
void FlutterTtsTizenPluginRegisterWithRegistrar (
201
285
FlutterDesktopPluginRegistrarRef registrar) {
202
286
FlutterTtsTizenPlugin::RegisterWithRegistrar (
0 commit comments