我在写一些安卓程序,用的是beeware的toga,最近对文件权限等有所突破,为此,我想写一个简单的程序获取系统的tts语音朗读功能,因为我发现termux可以用系统的tts,我就认为java可以调用系统tts功能,于是问了deepseek。
python
import toga
from toga.style import Pack
from toga.style.pack import COLUMN, ROW
import threading
class SystemTTSApp(toga.App):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.tts_engine = None
self.tts_ready = False
def startup(self):
# 创建主容器
main_box = toga.Box(style=Pack(direction=COLUMN, padding=20, flex=1))
# 标题
title_label = toga.Label(
'语音朗读程序',
style=Pack(padding=(0, 0, 10, 0), font_size=20, font_weight='bold')
)
# 创建输入框
self.input_text = toga.TextInput(
placeholder='请输入要朗读的文字(中英文均可)...',
style=Pack(flex=0, padding=5)
)
# 创建测试按钮
test_button = toga.Button(
'测试TTS',
on_press=self.test_tts,
style=Pack(flex=1, padding=10, background_color='#4CAF50', color='white')
)
# 创建按钮
button_box = toga.Box(style=Pack(direction=ROW, padding=10))
display_button = toga.Button(
'显示文字',
on_press=self.display_text,
style=Pack(flex=1, padding=10)
)
speak_button = toga.Button(
'朗读文字',
on_press=self.speak_text,
style=Pack(flex=1, padding=10)
)
button_box.add(display_button)
button_box.add(speak_button)
# 显示区域 - 使用MultilineTextInput替代Label,支持自动换行
self.output_display = toga.MultilineTextInput(
readonly=True,
placeholder='这里将显示输入的文字',
style=Pack(flex=1, padding=10, font_size=14, background_color='#f5f5f5')
)
# 状态显示区域 - 同样使用MultilineTextInput,支持自动换行
self.status_display = toga.MultilineTextInput(
readonly=True,
placeholder='状态信息将在这里显示',
style=Pack(flex=0, padding=10, font_size=12, background_color='#e8f4f8', height=100)
)
# 添加到主容器
main_box.add(title_label)
main_box.add(self.input_text)
main_box.add(test_button)
main_box.add(button_box)
main_box.add(self.output_display)
main_box.add(self.status_display)
# 创建主窗口
self.main_window = toga.MainWindow(title=self.formal_name, size=(400, 600))
self.main_window.content = main_box
self.main_window.show()
# 初始化TTS
self.init_tts()
def init_tts(self):
"""初始化系统TTS引擎"""
self.update_status("正在初始化语音引擎...")
threading.Thread(target=self._init_tts_thread, daemon=True).start()
def _init_tts_thread(self):
"""在新线程中初始化TTS"""
try:
# 导入必要的Java类
from rubicon.java import JavaClass
# 获取TTS类
TextToSpeech = JavaClass('android.speech.tts.TextToSpeech')
Locale = JavaClass('java.util.Locale')
Context = JavaClass('android.content.Context')
# 获取当前Activity
activity = self.main_window._impl.app.native
# 创建TTS引擎
self.tts_engine = TextToSpeech(activity, None)
# 检查初始化状态
import time
time.sleep(1) # 等待初始化完成
# 设置语言
result = self.tts_engine.setLanguage(Locale.CHINESE)
if result == TextToSpeech.LANG_MISSING_DATA:
self.update_status("❌ TTS初始化失败:缺少中文语音数据\n请安装中文TTS语音包")
self.tts_ready = False
elif result == TextToSpeech.LANG_NOT_SUPPORTED:
self.update_status("❌ TTS初始化失败:不支持中文\n尝试使用默认语言")
self.tts_engine.setLanguage(Locale.getDefault())
self.tts_ready = True
self.update_status("✅ TTS已就绪(使用默认语言)")
elif result == TextToSpeech.SUCCESS:
self.update_status("✅ TTS已就绪(支持中文)")
self.tts_ready = True
else:
self.update_status(f"❌ TTS初始化失败:未知错误代码 {result}")
self.tts_ready = False
# 检查TTS引擎详细信息
engines = self.tts_engine.getEngines()
default_engine = self.tts_engine.getDefaultEngine()
self.update_status(f"可用引擎: {engines}\n默认引擎: {default_engine}")
except Exception as e:
import traceback
error_details = traceback.format_exc()
self.update_status(f"""
❌ TTS初始化失败:
错误信息:
{str(e)}
详细错误:
{error_details}
可能的原因:
1. 设备没有安装TTS引擎
2. 应用缺少TTS权限
3. 不支持当前Android版本
建议操作:
1. 安装Google Text-to-Speech引擎
2. 在系统设置中检查TTS配置
3. 重启设备后重试
""")
self.tts_ready = False
def test_tts(self, widget):
"""测试TTS功能"""
self.update_status("开始测试TTS功能...")
if not self.tts_ready or not self.tts_engine:
self.update_status("TTS引擎未初始化,无法测试")
return
# 测试朗读
test_text = "您好,这是一个测试语音。Hello, this is a test."
# 在新线程中测试
threading.Thread(target=self._test_tts_thread, args=(test_text,), daemon=True).start()
def _test_tts_thread(self, text):
"""在新线程中测试TTS"""
try:
from rubicon.java import JavaClass
TextToSpeech = JavaClass('android.speech.tts.TextToSpeech')
# 更新状态
self.update_status(f"🔊 测试朗读: {text}")
# 使用不同的参数测试
test_params = [
(TextToSpeech.QUEUE_FLUSH, None, "test_1"),
(TextToSpeech.QUEUE_ADD, None, "test_2"),
]
# 测试不同的语音模式和设置
self.tts_engine.setPitch(1.0) # 正常音调
self.tts_engine.setSpeechRate(1.0) # 正常语速
# 朗读测试文字
result = self.tts_engine.speak(
text,
TextToSpeech.QUEUE_FLUSH,
None,
"tts_test"
)
self.update_status(f"朗读结果代码: {result}")
if result == TextToSpeech.SUCCESS:
self.update_status("✅ 测试成功:朗读已开始")
# 等待朗读完成
import time
time.sleep(3) # 等待3秒让朗读完成
# 检查是否正在朗读
is_speaking = self.tts_engine.isSpeaking()
self.update_status(f"是否正在朗读: {is_speaking}")
if is_speaking:
self.update_status("✅ TTS工作正常,正在播放声音")
else:
self.update_status("⚠️ TTS没有播放声音,但返回了成功代码")
else:
self.update_status("❌ 测试失败:无法开始朗读")
except Exception as e:
self.update_status(f"❌ 测试失败: {str(e)}")
def update_status(self, message):
"""更新状态显示"""
self.main_window.app._impl.loop.call_soon_threadsafe(
lambda: setattr(self.status_display, 'value', message)
)
def update_output(self, message):
"""更新输出显示"""
self.main_window.app._impl.loop.call_soon_threadsafe(
lambda: setattr(self.output_display, 'value', message)
)
def display_text(self, widget):
"""显示文字"""
input_text = self.input_text.value
if input_text:
self.update_output(f"📝 输入的内容是:\n\n{input_text}")
self.update_status("文字已显示")
else:
self.update_output("⚠️ 请输入一些文字...")
self.update_status("输入框为空")
def speak_text(self, widget):
"""朗读文字"""
input_text = self.input_text.value
if not input_text:
self.update_status("请输入要朗读的文字")
return
if not self.tts_ready or not self.tts_engine:
self.update_status("TTS引擎未就绪,请先点击'测试TTS'按钮")
return
# 在新线程中朗读,避免阻塞UI
threading.Thread(target=self._speak_thread, args=(input_text,), daemon=True).start()
def _speak_thread(self, text):
"""在新线程中执行朗读"""
try:
from rubicon.java import JavaClass
TextToSpeech = JavaClass('android.speech.tts.TextToSpeech')
# 更新状态
self.update_status("🔊 正在朗读...")
self.update_output(f"🔊 正在朗读:\n\n{text}")
# 设置参数
self.tts_engine.setPitch(1.0) # 正常音调
self.tts_engine.setSpeechRate(0.9) # 稍微慢一点,更容易听清
# 朗读文字
result = self.tts_engine.speak(
text,
TextToSpeech.QUEUE_FLUSH,
None,
f"tts_{hash(text)}" # 唯一的utterance ID
)
self.update_status(f"朗读调用结果代码: {result}")
if result == TextToSpeech.SUCCESS:
self.update_status("✅ 朗读已开始")
# 等待朗读完成(简单延时)
import time
estimated_time = min(len(text) * 0.15, 10.0) # 最多等待10秒
time.sleep(estimated_time)
self.update_status("✅ 朗读应该已完成")
else:
self.update_status(f"❌ 无法开始朗读,错误代码: {result}")
except Exception as e:
error_msg = str(e)
self.update_status(f"❌ 朗读出错:\n\n{error_msg}")
def main():
return SystemTTSApp('语音朗读', 'com.example.ttsapp')
if __name__ == '__main__':
app = main()
app.main_loop()
这个程序好像不用怎么设置就可以在Android12上使用。在Android15上,发现不能用。为此再一直问deepseek,但他的回答越来越复杂,所以我还是最终用这个py文件。
在AndroidManifest.xml 加上相关内容:
XML
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.ttsdiagnostic">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<!-- TTS相关权限 -->
<uses-permission android:name="android.permission.BIND_TTS_SERVICE" />
<application
android:allowBackup="true"
android:icon="@mipmap/icon"
android:label="@string/app_name"
android:theme="@style/AppTheme">
<activity
android:name=".MainActivity"
android:configChanges="orientation|screenSize|keyboardHidden"
android:label="@string/app_name"
android:screenOrientation="portrait">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<!-- TTS引擎查询 -->
<queries>
<intent>
<action android:name="android.intent.action.TTS_SERVICE" />
</intent>
</queries>
</application>
</manifest>
pyproject.toml文件加上:requires = [
"rubicon-java",
]
我感觉可以不加。
安卓系统没有文字转语音,该怎么进行tts转语音
下载需要的应用
链接:https://pan.baidu.com/s/1zb3EUNRAaG_6rfiE8gtVHg
提取码:y68z