droid_wrap/android/speech/tts.rs
1/*
2 * Copyright (c) 2024. The RigelA open source project team and
3 * its contributors reserve all rights.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
9 * Unless required by applicable law or agreed to in writing, software distributed under the
10 * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 * See the License for the specific language governing permissions and limitations under the License.
12 */
13
14use crate::{
15 JObjNew, JObjRef, JProxy, JType, Result,
16 android::{content::Context, os::Bundle},
17 java::lang::CharSequence,
18 java_class, java_constructor, java_implement, java_interface, java_method,
19};
20use std::sync::Arc;
21
22/**
23从文本合成语音以立即播放或创建声音文件。 TextToSpeech 实例只有在完成初始化后才可用于合成文本。实现 TextToSpeech.OnInitListener 以接收初始化完成的通知。使用完 TextToSpeech 实例后,调用 shutdown() 方法释放 TextToSpeech 引擎使用的原生资源。针对 Android 11 且使用文本转语音的应用应在其清单的查询元素中声明 TextToSpeech.Engine.INTENT_ACTION_TTS_SERVICE:
24<queries>
25 ...
26 <intent>
27 <action android:name="android. intent. action. TTS_SERVICE" />
28 </intent>
29</queries>
30*/
31#[java_class(name = "android/speech/tts/TextToSpeech")]
32pub struct TextToSpeech;
33
34impl TextToSpeech {
35 /// 广播操作:TextToSpeech 合成器已完成对语音队列中所有文本的处理。
36 /// 请注意,当引擎完成文本数据处理时,这会通知呼叫者。此时音频播放可能尚未完成(甚至尚未开始)。如果您希望在发生这种情况时收到通知,请参阅 TextToSpeech.OnUtteranceCompletedListener。
37 pub const ACTION_TTS_QUEUE_PROCESSING_COMPLETED: &'static str =
38 "android.speech.tts.TTS_QUEUE_PROCESSING_COMPLETED";
39
40 /// 表示一般操作失败。
41 pub const ERROR: i32 = -1;
42
43 /// 表示由无效请求导致的失败。
44 pub const ERROR_INVALID_REQUEST: i32 = -8;
45
46 /// 表示由网络连接问题导致的故障。
47 pub const ERROR_NETWORK: i32 = -6;
48
49 /// 表示由于网络超时导致的失败。
50 pub const ERROR_NETWORK_TIMEOUT: i32 = -7;
51
52 /// 表示由于语音数据未下载完成而导致的失败。
53 pub const ERROR_NOT_INSTALLED_YET: i32 = -9;
54
55 /// 表示与输出(音频设备或文件)相关的故障。
56 pub const ERROR_OUTPUT: i32 = -5;
57
58 /// 表示 TTS 引擎无法合成给定的输入。
59 pub const ERROR_SYNTHESIS: i32 = -3;
60
61 /// 表示该语言适用于该区域设置的语言,但不适用于该国家/地区和变体。
62 pub const LANG_AVAILABLE: i32 = 0;
63
64 /// 表示该语言适用于区域设置指定的语言和国家/地区,但不适用于变体。
65 pub const LANG_COUNTRY_AVAILABLE: i32 = 1;
66
67 /// 表示该语言完全按照区域设置指定的方式提供。
68 pub const LANG_COUNTRY_VAR_AVAILABLE: i32 = 2;
69
70 /// 表示缺少语言数据。
71 pub const LANG_MISSING_DATA: i32 = -1;
72
73 /// 表示不支持该语言。
74 pub const LANG_NOT_SUPPORTED: i32 = -2;
75
76 /// 队列模式,新条目添加到播放队列的末尾。
77 pub const QUEUE_ADD: i32 = 1;
78
79 /// 队列模式,其中整个播放队列都会被清除。这与 QUEUE_FLUSH 不同,因为所有条目都会被清除,而不仅仅是来自给定调用者的条目。
80 pub const QUEUE_DESTROY: i32 = 2;
81
82 /// 队列模式,播放队列中的所有条目(要播放的媒体和要合成的文本)都将被删除并替换为新条目。队列会根据给定的调用应用进行刷新。队列中来自其他调用者的条目不会被丢弃。
83 pub const QUEUE_FLUSH: i32 = 0;
84
85 /// 表示客户端请求停止。它仅在 API 的服务端使用,客户端不应该期望看到此结果代码。
86 pub const STOPPED: i32 = -2;
87
88 /// 表示操作成功。
89 pub const SUCCESS: i32 = 0;
90
91 /// 表示 TTS 服务失败。
92 pub const ERROR_SERVICE: i32 = -4;
93
94 /**
95 TextToSpeech 类的构造函数,使用默认的 TTS 引擎。如果尚未运行,这还将初始化关联的 TextToSpeech 引擎。
96 `context` 此实例正在运行的上下文。
97 `listener` 当 TextToSpeech 引擎初始化时将调用 TextToSpeech.OnInitListener。如果发生故障,可能会在 TextToSpeech 实例完全构造之前立即调用侦听器。
98 */
99 #[java_constructor]
100 pub fn new<L: TextToSpeech_OnInitListener>(context: &Context, listener: &L) -> Self {}
101
102 /**
103 中断当前话语(无论是播放还是渲染到文件)并丢弃队列中的其他话语。
104 返回:错误或成功。
105 */
106 #[java_method]
107 pub fn stop(&self) -> i32 {}
108
109 /**
110 检查 TTS 引擎是否正在讲话。请注意,一旦语音项目的音频数据被发送到音频混音器或写入文件,该语音项目即被视为完成。此时与音频硬件完成播放之间可能会有有限地滞后。如果 TTS 引擎正在讲话,则返回 true。
111 */
112 #[java_method]
113 pub fn is_speaking(&self) -> bool {}
114
115 /**
116 释放 TextToSpeech 引擎使用的资源。例如,在 Activity 的 onDestroy() 方法中调用此方法是一种很好的做法,这样 TextToSpeech 引擎就可以完全停止。
117 */
118 #[java_method]
119 pub fn shutdown(&self) {}
120
121 /**
122 设置 TextToSpeech 引擎的语音音调。这对任何预录语音均无影响。
123 返回:ERROR 或 SUCCESS。
124 `pitch` 语音音调。1.0 为正常音调,值越低,合成语音的音调越低,值越高,合成语音的音调越高。
125 */
126 #[java_method]
127 pub fn set_pitch(&self, pitch: f32) -> i32 {}
128
129 /**
130 设置语速。这对任何预先录制的语音没有影响。
131 返回:ERROR 或 SUCCESS。
132 `speech_rate` 语速。1.0 是正常语速,较低的值会减慢语速(0.5 是正常语速的一半),较高的值会加快语速(2.0 是正常语速的两倍)。
133 */
134 #[java_method]
135 pub fn set_speech_rate(&self, speech_rate: f32) -> i32 {}
136
137 //noinspection SpellCheckingInspection
138 /**
139 设置要使用的 TTS 引擎。
140 返回:ERROR 或 SUCCESS。
141 `engine_package_name` 合成引擎的包名称(例如“com.svox.pico”)
142 */
143 #[java_method]
144 #[deprecated(
145 note = "这不会在 TTS 引擎初始化时通知调用者。TextToSpeech(Context, TextToSpeech.OnInitListener, String) 可以与适当的引擎名称一起使用。此外,不能保证指定的引擎将被加载。如果未安装或禁用,则将应用用户/系统范围的默认值。"
146 )]
147 pub fn set_engine_by_package_name(&self, engine_package_name: String) -> i32 {}
148
149 /**
150 传递给 Speaking 和 SynthesizeToFile 的输入字符串的长度限制。
151 */
152 #[java_method]
153 pub fn get_max_speech_input_length() -> i32 {}
154
155 /**
156 获取默认语音合成引擎的包装名称。
157 返回:用户选择的TTS引擎的软件包名称作为其默认值。
158 */
159 #[java_method]
160 pub fn get_default_engine(&self) -> String {}
161
162 /**
163 返回:此 TextToSpeech 实例当前使用的引擎。
164 */
165 #[java_method]
166 pub fn get_current_engine(&self) -> String {}
167
168 //noinspection SpellCheckingInspection
169 /**
170 检查用户的设置是否应覆盖调用应用程序请求的设置。
171 */
172 #[java_method]
173 #[deprecated(note = "从 Ice creamwich 版本开始,用户设置永远不会强制覆盖应用程序的设置。")]
174 pub fn are_defaults_enforced(&self) -> bool {}
175
176 //noinspection SpellCheckingInspection
177 /**
178 使用指定的排队策略和语音参数朗读文本,文本可能以 TtsSpans 为单位。此方法是异步的,即该方法只是将请求添加到 TTS 请求队列然后返回。当此方法返回时,合成可能尚未完成(甚至尚未开始!)。为了可靠地检测合成过程中的错误,我们建议设置一个发音进度监听器(参见 setOnUtteranceProgressListener)并使用 TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID 参数。
179 返回:排队发言操作的错误或成功。
180 `text` 要朗读的文本字符串。长度不超过 getMaxSpeechInputLength() 字符。
181 `queue_mode` 要使用的排队策略,QUEUE_ADD 或 QUEUE_FLUSH。
182 `params` 请求的参数。可以为 null。支持的参数名称:TextToSpeech.Engine.KEY_PARAM_STREAM、TextToSpeech.Engine.KEY_PARAM_VOLUME、TextToSpeech.Engine。KEY_PARAM_PAN。可以传入引擎特定参数,但参数键必须以它们所针对的引擎的名称作为前缀。例如,如果正在使用名为“com.svox.pico”的引擎,则键“com.svox.pico_foo”和“com.svox.pico:bar”将传递给该引擎。
183 `utterance_id` 此请求的唯一标识符。
184 */
185 #[java_method]
186 pub fn speak<CS: CharSequence>(
187 &self,
188 text: &CS,
189 queue_mode: i32,
190 params: Option<Bundle>,
191 utterance_id: String,
192 ) -> i32 {
193 }
194}
195
196/**
197调用回调接口定义,指示 TextToSpeech 引擎初始化完成。
198*/
199#[allow(non_camel_case_types)]
200#[java_interface(name = "android/speech/tts/TextToSpeech$OnInitListener")]
201pub trait TextToSpeech_OnInitListener {
202 /**
203 调用以表示 TextToSpeech 引擎初始化完成。
204 `status` 成功或错误。
205 */
206 fn on_init(&self, status: i32);
207}
208
209#[doc(hidden)]
210#[allow(non_camel_case_types)]
211#[java_class(name = "android/speech/tts/TextToSpeech$OnInitListenerImpl")]
212pub struct TextToSpeech_OnInitListenerImpl(Box<dyn Fn(i32) + Send + Sync>);
213
214#[java_implement]
215impl TextToSpeech_OnInitListener for TextToSpeech_OnInitListenerImpl {
216 fn on_init(&self, status: i32) {
217 self.0(status)
218 }
219}
220
221impl Default for TextToSpeech_OnInitListenerImplDefault {
222 fn default() -> Self {
223 Self(Box::new(|_| ()))
224 }
225}
226
227impl TextToSpeech_OnInitListenerImpl {
228 pub fn from_fn(func: impl Fn(/* status */ i32) + Send + Sync + 'static) -> Result<Arc<Self>> {
229 Self::new(TextToSpeech_OnInitListenerImplDefault(Box::new(func)))
230 }
231}
232
233//noinspection SpellCheckingInspection
234/// 测试android.speech.tts
235#[cfg(feature = "test_android_speech_tts")]
236pub fn test() {
237 use crate::{
238 android::app::Activity,
239 java::lang::{CharSequenceExt, CharSequenceImpl},
240 };
241 let context = Activity::fetch().unwrap();
242 let init_listener = TextToSpeech_OnInitListenerImpl::from_fn(|status| {
243 println!("Tts is initialized status: {}.", status)
244 })
245 .unwrap();
246 let tts = TextToSpeech::new(&context, init_listener.as_ref());
247 assert!(
248 tts.to_string()
249 .starts_with("android.speech.tts.TextToSpeech")
250 );
251 tts.stop();
252 assert_eq!(false, tts.is_speaking());
253 assert_eq!(TextToSpeech::SUCCESS, tts.set_pitch(0.8f32));
254 assert_eq!(TextToSpeech::SUCCESS, tts.set_speech_rate(0.8f32));
255 // assert_eq!(TextToSpeech::SUCCESS, tts.set_engine_by_package_name("com.sgr.grtts".to_string()));
256 assert!(!tts.get_default_engine().is_empty());
257 assert!(!tts.get_current_engine().is_empty());
258 // dbg!(tts.are_defaults_enforced());
259 tts.speak(
260 &"你好".to_char_sequence::<CharSequenceImpl>().unwrap(),
261 TextToSpeech::QUEUE_ADD,
262 None,
263 "test".to_string(),
264 );
265 tts.shutdown();
266 assert!(TextToSpeech::get_max_speech_input_length() > 0);
267}