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