- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
我需要实例化一个 TextToSpeech 对象并设置给定的语言(以编程方式设置并且可能会有所不同)。我知道我可以使用 setLanguage() 但只有当语言在特定 TextToSpeech 实例正在使用的 TTS 引擎中可用时才有效。我知道我可以通过 myTTS.isLanguageAvailable() 检查一种语言是否可用,但这只会告诉我该语言在当前引擎上是否可用。
问题是用户可能安装了多个 TTS 引擎,其中一个可能提供了所需的语言,但默认的没有。在那种情况下,我想找到引擎,使用它并设置语言。
所以我需要遍历可用的 TTS 引擎并“询问”每个引擎是否有所需的可用语言。
我试过这个:
mUserLocale=new Locale("it-IT"); //just an example
mTextToSpeech=new TextToSpeech(getApplicationContext(), this);
if (mTextToSpeech.isLanguageAvailable(mUserLocale)<0) {
List<TextToSpeech.EngineInfo> engines=mTextToSpeech.getEngines();
int currentmatchquality=-1;
String defaultTTSEngine=mTextToSpeech.getDefaultEngine();
mTextToSpeech.shutdown();
mTextToSpeech=null;
for (int i=0; i<engines.size(); i++) {
TextToSpeech.EngineInfo engineinfo=engines.get(i);
Log.d("MainActivity", "Examining TTS engine "+engineinfo.name);
if (engineinfo.name.equals(defaultTTSEngine)) {
Log.d("MainActivity", "Skipping default TTS engine "+engineinfo.name);
continue;
}
TextToSpeech candidateTTS=new TextToSpeech(getApplicationContext(),this,engineinfo.name);
int matchquality=candidateTTS.isLanguageAvailable(mUserLocale);
if (matchquality>currentmatchquality) {
Log.d("MainActivity", "Selecting TTS engine "+engineinfo.name);
mTextToSpeech.shutdown();
mTextToSpeech=candidateTTS;
mTTSEngine=engineinfo.name;
currentmatchquality=matchquality;
}
else {
Log.d("MainActivity", " "+mUserLocale.toString()+" not available on this engine: "+matchquality);
}
}
if (mTTSEngine==null) mTTSEngine=defaultTTSEngine;
mTextToSpeech=new TextToSpeech(getApplicationContext(),this,mTTSEngine);
}
if (mTextToSpeech.isLanguageAvailable(mUserLocale)>=0) mTextToSpeech.setLanguage(mUserLocale);
问题是我系统地从 isLanguageAvailable 得到 -2:
D/MainActivity﹕ Examining TTS engine com.google.android.tts
I/TextToSpeech﹕ Sucessfully bound to com.google.android.tts
W/TextToSpeech﹕ isLanguageAvailable failed: not bound to TTS engine
D/MainActivity﹕ it-it not available on this engine: -2
我猜这是因为我需要等待 TTS 的初始化事件,然后才能查询可用语言。
那会很麻烦。有没有一种方法可以循环遍历现有的 TTS 引擎并检查它们中的每一个是否有一种语言可用(或获取每个引擎的所有可用语言的列表)而无需为每个引擎实例化 TextToSpeech 对象并等待它被初始化?
最佳答案
这是我用于调试的设置 - 您可以在生产中使用它的元素:
// Container Class
public class ContainerVoiceEngine {
private String label;
private String packageName;
private ArrayList<String> voices;
private Intent intent;
public ContainerVoiceEngine() {
}
public ContainerVoiceEngine(final String label, final String packageName, final ArrayList<String> voices, final Intent intent) {
this.label = label;
this.packageName = packageName;
this.voices = voices;
this.intent = intent;
}
public Intent getIntent() {
return intent;
}
public void setIntent(final Intent intent) {
this.intent = intent;
}
public String getLabel() {
return label;
}
public void setLabel(final String label) {
this.label = label;
}
public String getPackageName() {
return packageName;
}
public void setPackageName(final String packageName) {
this.packageName = packageName;
}
public ArrayList<String> getVoices() {
return voices;
}
public void setVoices(final ArrayList<String> voices) {
this.voices = voices;
}
}
// Usage within an Activity - Debugging only!
private ArrayList<ContainerVoiceEngine> containerVEArray;
private int requestCount;
private void getEngines() {
requestCount = 0;
final Intent ttsIntent = new Intent();
ttsIntent.setAction(TextToSpeech.Engine.ACTION_CHECK_TTS_DATA);
final PackageManager pm = getPackageManager();
final List<ResolveInfo> list = pm.queryIntentActivities(ttsIntent, PackageManager.GET_META_DATA);
containerVEArray = new ArrayList<ContainerVoiceEngine>(list.size());
for (int i = 0; i < list.size(); i++) {
final ContainerVoiceEngine cve = new ContainerVoiceEngine();
cve.setLabel(list.get(i).loadLabel(pm).toString());
cve.setPackageName(list.get(i).activityInfo.applicationInfo.packageName);
final Intent getIntent = new Intent();
getIntent.setAction(TextToSpeech.Engine.ACTION_CHECK_TTS_DATA);
getIntent.setPackage(cve.getPackageName());
getIntent.getStringArrayListExtra(TextToSpeech.Engine.EXTRA_AVAILABLE_VOICES);
getIntent.getStringArrayListExtra(TextToSpeech.Engine.EXTRA_UNAVAILABLE_VOICES);
cve.setIntent(getIntent);
containerVEArray.add(cve);
}
Log.d("TAG", "containerVEArray: " + containerVEArray.size());
for (int i = 0; i < containerVEArray.size(); i++) {
startActivityForResult(containerVEArray.get(i).getIntent(), i);
}
}
@Override
public void onActivityResult(final int requestCode, final int resultCode, final Intent data) {
Log.i("TAG", "onActivityResult: requestCount: " + " - requestCode: " + requestCode);
requestCount++;
try {
if (data != null) {
final Bundle bundle = data.getExtras();
if (bundle != null) {
Log.d("TAG", containerVEArray.get(requestCode).getLabel() + " - Bundle Data");
final Set<String> keys = bundle.keySet();
final Iterator<String> it = keys.iterator();
while (it.hasNext()) {
final String key = it.next();
Log.d("TAG", "Key: " + key + " = " + bundle.get(key));
}
}
if (data.hasExtra("availableVoices")) {
containerVEArray.get(requestCode).setVoices(data.getStringArrayListExtra("availableVoices"));
} else {
containerVEArray.get(requestCode).setVoices(new ArrayList<String>());
}
}
if (requestCount == containerVEArray.size()) {
for (int i = 0; i < containerVEArray.size(); i++) {
Log.v("TAG", "cve: " + containerVEArray.get(i).getLabel() + " - "
+ containerVEArray.get(i).getVoices().size() + " - " + containerVEArray.get(i).getVoices().toString());
}
}
} catch (final IndexOutOfBoundsException e) {
Log.e("TAG", "IndexOutOfBoundsException");
e.printStackTrace();
} catch (final NullPointerException e) {
Log.e("TAG", "NullPointerException");
e.printStackTrace();
} catch (final Exception e) {
Log.e("TAG", "Exception");
e.printStackTrace();
}
}
希望对您有所帮助。
编辑
根据您的评论,这些“声音”实际上是语言,从某种意义上说,它们在其结构中返回具有代表性的语言环境。但请注意,Locale 与 System Locale 的格式不同,这真的很烦人,需要在未来的 Android 更新中进行排序。
看看my answer here关于使用 tts.setLanguage(Locale) 的陷阱。该问题还涉及创建语言环境 - Locale loc = new Locale(String)。
您可以对可用语言的 ArrayList 使用循环,以尝试为每个引擎从每个语言构建一个 Locale。
希望对您有所帮助。
关于android - 如何在不实例化每个语言并等待初始化的情况下轮询可用的 TTS 引擎以获取可用语言,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25700155/
我是 Java 新手,这是我的代码, if( a.name == b.name && a.displayname == b.displayname && a.linknam
在下面的场景中,我有一个 bool 值。根据结果,我调用完全相同的函数,唯一的区别是参数的数量。 var myBoolean = ... if (myBoolean) { retrieve
我是一名研究 C++ 的 C 开发人员: 我是否正确理解如果我抛出异常然后堆栈将展开直到找到第一个异常处理程序?是否可以在不展开的情况下在任何 throw 上打开调试器(即不离开声明它的范围或任何更高
在修复庞大代码库中的错误时,我观察到一个奇怪的情况,其中引用的动态类型从原始 Derived 类型更改为 Base 类型!我提供了最少的代码来解释问题: struct Base { // some
我正在尝试用 C# 扩展给定的代码,但由于缺乏编程经验,我有点陷入困境。 使用 Visual Studio 社区,我尝试通过控制台读出 CPU 核心温度。该代码使用开关/外壳来查找传感器的特定名称(即
这可能是一个哲学问题。 假设您正在向页面发出 AJAX 请求(这是使用 Prototype): new Ajax.Request('target.asp', { method:"post", pa
我有以下 HTML 代码,我无法在所有浏览器中正常工作: 我试图在移动到
我对 Swift 很陌生。我如何从 addPin 函数中检索注释并能够在我的 addLocation 操作 (buttonPressed) 中使用它。我正在尝试使用压力触摸在 map 上添加图钉,在两
我设置了一个详细 View ,我是否有几个 Nib 文件根据在 Root View Controller 的表中选择的项目来加载。 我发现,对于 Nibs 的类,永远不会调用 viewDidUnloa
我需要动态访问 json 文件并使用以下代码。在本例中,“bpicsel”和“temp”是变量。最终结果类似于“data[0].extit1” var title="data["+bpicsel+"]
我需要使用第三方 WCF 服务。我已经在我的证书存储中配置了所需的证书,但是在调用 WCF 服务时出现以下异常。 向 https://XXXX.com/AHSharedServices/Custome
在几个 SO 答案(1、2)中,建议如果存在冲突则不应触发 INSERT 触发器,ON CONFLICT DO NOTHING 在触发语句中。也许我理解错了,但在我的实验中似乎并非如此。 这是我的 S
如果进行修改,则会给出org.hibernate.NonUniqueObjectException。在我的 BidderBO 类(class)中 @Override @Transactional(pr
我使用 indexOf() 方法来精细地查找数组中的对象。 直到此刻我查了一些资料,发现代码应该无法正常工作。 我在reducer中尝试了上面的代码,它成功了 let tmp = state.find
假设我有以下表格: CREATE TABLE Game ( GameID INT UNSIGNED NOT NULL, GameType TINYINT UNSIGNED NOT NU
代码: Alamofire.request(URL(string: imageUrl)!).downloadProgress(closure: { (progress) in
我是一名优秀的程序员,十分优秀!