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}