如何在不实例化每种TTS引擎并等待初始化的情况下轮询可用的TTS引擎以获取可用的语言 [英] How to poll available TTS engines for available languages without instantiating each one and wating for init

查看:130
本文介绍了如何在不实例化每种TTS引擎并等待初始化的情况下轮询可用的TTS引擎以获取可用的语言的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要实例化TextToSpeech对象并设置给定的语言(该语言是通过编程方式设置的,可能会有所不同). 我知道我可以使用setLanguage(),但是只有当特定TextToSpeech实例正在使用的TTS引擎中提供了该语言时,该语言才能起作用. 我知道我可以通过myTTS.isLanguageAvailable()检查语言是否可用,但这只会告诉我该语言在当前引擎上是否可用.

I need to instantiate a TextToSpeech object and set a given language (which is set programmatically and may vary). I know I can use setLanguage() but that will only work if the language is available in the TTS engine that partictual TextToSpeech instance is using. I know I can check whether a language is available by means of myTTS.isLanguageAvailable() but that will only tell me whether the language is available on the current engine.

问题是用户可能安装了多个TTS引擎,并且所需的语言可能是其中之一,而不是默认语言.在这种情况下,我想找到引擎,使用它并设置语言.

The problem is that the user may have more than one TTS engine installed and the desired language may be available in one of them but not in the default one. In that case I want to find the engine, use it and set the language.

因此,我需要遍历可用的TTS引擎,并询问"每个引擎是否具有所需的可用语言.

So I need to loop through the available TTS engines and "ask" each one whether it has the desired language available.

我已经尝试过了:

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:

The problem is that I systematically get -2 as the result from isLanguageAvailable:

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的init事件,然后才能查询它的可用语言.

I guess it's because I need to wait for the init event of the TTS before I query it for an available language.

那将很麻烦. 有没有一种方法可以遍历现有的TTS引擎并检查每种语言是否可用(或获取每个引擎所有可用语言的列表),而无需为每个引擎实例化TextToSpeech对象并等待其初始化?

That would be cumbersome. Is there a way to loop through existing TTS engines and check whether a language is available in each of them (or get a list of all available languages per engine) without instantiating a TextToSpeech object for each engine and waiting for it to be initialized??

推荐答案

这是我用于调试的设置-您可以在生产环境中使用它的元素:

Here is the setup I use for debugging - You could use elements of it in production:

// 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();
        }
    }

希望有帮助.

修改

根据您的评论,这些语音"实际上是语言,在某种意义上说,它们在结构上返回了代表性的语言环境.不过请注意,语言环境与系统语言环境的格式不同,这确实很烦人,需要在以后的Android更新中进行排序.

Further to your comment, these 'voices' are in actual fact the languages, in the sense that they return a representative Locale in their structure. Be aware though, the Locale is in a different format to the System Locale, which is really annoying and needs to be sorted in a future Android update.

在这里我的答案中,了解有关使用tts.setLanguage(Locale)的陷阱.该问题还涉及创建语言环境-Locale loc = new Locale(String).

Take a look at my answer here regarding the pitfalls with using tts.setLanguage(Locale). The question also deals with creating a Locale - Locale loc = new Locale(String).

您可以对可用语言的ArrayList使用循环,以尝试为每种引擎从每种语言构造一个语言环境.

You can use a loop for the ArrayList of available languages to try and construct a Locale from each, for each Engine.

希望有帮助.

这篇关于如何在不实例化每种TTS引擎并等待初始化的情况下轮询可用的TTS引擎以获取可用的语言的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆