关于语音识别的 Android 附加功能不起作用

Posted

技术标签:

【中文标题】关于语音识别的 Android 附加功能不起作用【英文标题】:Android extras about speech recognition does not work 【发布时间】:2013-03-17 15:35:13 【问题描述】:

我目前正忙于语音识别,我希望语音识别器能够持续不断地听我说话。该应用程序的目的是等待特定关键字的语音:当用户说出这个关键字时,服务准备好接收用户语音命令经过研究我发现我们可以操纵识别器收听的时间。通过这些常量:

顺便说一下,默认识别器服务侦听大约 10 秒。 (谷歌 API)

     String EXTRA_SPEECH_INPUT_COMPLETE_SILENCE_LENGTH_MILLIS   The amount of time that it should take after we stop hearing speech to consider the input complete.
     String EXTRA_SPEECH_INPUT_MINIMUM_LENGTH_MILLIS    The minimum length of an utterance.
     String EXTRA_SPEECH_INPUT_POSSIBLY_COMPLETE_SILENCE_LENGTH_MILLIS  The amount of time that it should take after we stop hearing speech to consider the input possibly complete.

http://java.llp2.dcc.ufmg.br/apiminer/docs/reference/android/speech/RecognizerIntent.html

这些是 bundle 类的附加功能。

问题是,当我在代码中使用这些常量时,它不起作用。

这是我的代码:

   intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_MINIMUM_LENGTH_MILLIS, 5000);
   intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_COMPLETE_SILENCE_LENGTH_MILLIS, 5000);
   intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_POSSIBLY_COMPLETE_SILENCE_LENGTH_MILLIS, 5000);

如你所见,尽管我写了 5000 毫秒,但识别器仍会听我大约 10 秒。

你能想到问题吗?也许我不知道如何使用 extras,或者可能是关于权限,也许它跳过了我的代码或者我应该添加一些其他代码。

如有任何帮助,将不胜感激。

编辑:这是我的完整代码:

VoiceRecognitionActivity.java

public class VoiceRecognitionActivity extends Activity implements
    TextToSpeech.OnInitListener 

private static final int REQUEST_CODE = 1234;
private Button mTalkButton;
private ListView wordsList;

@Override
public void onCreate(Bundle savedInstanceState) 
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_voice_recognition);
    mTalkButton = (Button) findViewById(R.id.talk_button);
    wordsList = (ListView) findViewById(R.id.listView1);
    // Disable button if no recognition service is present
    PackageManager pm = getPackageManager();
    List<ResolveInfo> activities = pm.queryIntentActivities(new Intent(
            RecognizerIntent.ACTION_RECOGNIZE_SPEECH), 0);
    if (activities.size() == 0) 
        mTalkButton.setEnabled(false);
        mTalkButton.setText("Recognizer not present");
     else 
        mTalkButton.setOnClickListener(new OnClickListener() 

            @Override
            public void onClick(View v) 
                Intent intent = new Intent(
                        RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
                intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL,
                        RecognizerIntent.LANGUAGE_MODEL_FREE_FORM);
                intent.putExtra(RecognizerIntent.EXTRA_PROMPT,
                        "Voice recognition Demo...");
                String defaultLanguage = Locale
                        .getDefault().toString();
                intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, Locale
                        .getDefault());

                intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_MINIMUM_LENGTH_MILLIS, 5000);
                intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_COMPLETE_SILENCE_LENGTH_MILLIS, 5000);
                intent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_POSSIBLY_COMPLETE_SILENCE_LENGTH_MILLIS, 5000);

                startActivityForResult(intent, REQUEST_CODE);

            
        );
    


/**
 * Handle the results from the voice recognition activity.
 */
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) 
    if (requestCode == REQUEST_CODE && resultCode == RESULT_OK) 
        // Populate the wordsList with the String values the recognition
        // engine thought it heard
        ArrayList<String> matches = data
                .getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS);
        wordsList.setAdapter(new ArrayAdapter<String>(this,
                android.R.layout.simple_list_item_1, matches));
    
    super.onActivityResult(requestCode, resultCode, data);


@Override
public boolean onCreateOptionsMenu(Menu menu) 
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.activity_voice_recognition, menu);
    return true;


@Override
public boolean onOptionsItemSelected(MenuItem item) 
    // Handle item selection
    switch (item.getItemId()) 
    case R.id.menu_settings:
        startActivity(new Intent(this, SettingsActivity.class));
        return true;

    default:
        return super.onOptionsItemSelected(item);
    


@Override
public void onInit(int status) 
    // TODO Auto-generated method stub


TTSUtils.java

公共类 TTSUtils 实现 TextToSpeech.OnInitListener

private TextToSpeech mTts;
private static TTSUtils mInstance;
private Context mContext;

public static TTSUtils getInstance(Context c) 
    if (mInstance == null) 
        mInstance = new TTSUtils(c);
    
    return mInstance;


private TTSUtils(Context c) 
    mContext = c;
    mTts = new TextToSpeech(mContext, this);
    mInstance = this;


@Override
public void onInit(int status) 
    // TODO Auto-generated method stub



public void destroyTTS() 
    if (mTts != null) 
        mTts.stop();
        mTts.shutdown();
    


public int setLanguage(Locale l) 
    return mTts.setLanguage(l);


public int speak(String s, int i, HashMap<String, String> h) 
    return mTts.speak(s, i, h);

SettingsActivity.java

公共类 SettingsActivity 扩展 PreferenceActivity

/**
 * Determines whether to always show the simplified settings UI, where
 * settings are presented in a single list. When false, settings are shown
 * as a master/detail two-pane view on tablets. When true, a single pane is
 * shown on tablets.
 */

private static final boolean ALWAYS_SIMPLE_PREFS = false;

@Override
protected void onPostCreate(Bundle savedInstanceState) 
    super.onPostCreate(savedInstanceState);

    setupSimplePreferencesScreen();


/**
 * Shows the simplified settings UI if the device configuration if the
 * device configuration dictates that a simplified, single-pane UI should be
 * shown.
 */
private void setupSimplePreferencesScreen() 
    if (!isSimplePreferences(this)) 
        return;
    

    // In the simplified UI, fragments are not used at all and we instead
    // use the older PreferenceActivity APIs.

    // Add 'general' preferences.
    addPreferencesFromResource(R.xml.pref_general);

    // Add 'notifications' preferences, and a corresponding header.
    PreferenceCategory fakeHeader = new PreferenceCategory(this);
    fakeHeader.setTitle(R.string.pref_header_notifications);
    getPreferenceScreen().addPreference(fakeHeader);
    addPreferencesFromResource(R.xml.pref_notification);

    // Add 'data and sync' preferences, and a corresponding header.
    fakeHeader = new PreferenceCategory(this);
    fakeHeader.setTitle(R.string.pref_header_data_sync);
    getPreferenceScreen().addPreference(fakeHeader);
    addPreferencesFromResource(R.xml.pref_data_sync);

    // Bind the summaries of EditText/List/Dialog/Ringtone preferences to
    // their values. When their values change, their summaries are updated
    // to reflect the new value, per the Android Design guidelines.
    bindPreferenceSummaryToValue(findPreference("example_text"));
    bindPreferenceSummaryToValue(findPreference("example_list"));
    bindPreferenceSummaryToValue(findPreference("notifications_new_message_ringtone"));
    bindPreferenceSummaryToValue(findPreference("sync_frequency"));


/** @inheritDoc */
@Override
public boolean onIsMultiPane() 
    return isXLargeTablet(this) && !isSimplePreferences(this);


/**
 * Helper method to determine if the device has an extra-large screen. For
 * example, 10" tablets are extra-large.
 */
private static boolean isXLargeTablet(Context context) 
    return (context.getResources().getConfiguration().screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) >= Configuration.SCREENLAYOUT_SIZE_XLARGE;


/**
 * Determines whether the simplified settings UI should be shown. This is
 * true if this is forced via @link #ALWAYS_SIMPLE_PREFS, or the device
 * doesn't have newer APIs like @link PreferenceFragment, or the device
 * doesn't have an extra-large screen. In these cases, a single-pane
 * "simplified" settings UI should be shown.
 */
private static boolean isSimplePreferences(Context context) 
    return ALWAYS_SIMPLE_PREFS
            || Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB
            || !isXLargeTablet(context);


/** @inheritDoc */
@Override
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
public void onBuildHeaders(List<Header> target) 
    if (!isSimplePreferences(this)) 
        loadHeadersFromResource(R.xml.pref_headers, target);
    


/**
 * A preference value change listener that updates the preference's summary
 * to reflect its new value.
 */
private static Preference.OnPreferenceChangeListener sBindPreferenceSummaryToValueListener = new Preference.OnPreferenceChangeListener() 
    @Override
    public boolean onPreferenceChange(Preference preference, Object value) 
        String stringValue = value.toString();

        if (preference instanceof ListPreference) 
            // For list preferences, look up the correct display value in
            // the preference's 'entries' list.
            ListPreference listPreference = (ListPreference) preference;
            int index = listPreference.findIndexOfValue(stringValue);

            // Set the summary to reflect the new value.
            preference
                    .setSummary(index >= 0 ? listPreference.getEntries()[index]
                            : null);

         else if (preference instanceof RingtonePreference) 
            // For ringtone preferences, look up the correct display value
            // using RingtoneManager.
            if (TextUtils.isEmpty(stringValue)) 
                // Empty values correspond to 'silent' (no ringtone).
                preference.setSummary(R.string.pref_ringtone_silent);

             else 
                Ringtone ringtone = RingtoneManager.getRingtone(
                        preference.getContext(), Uri.parse(stringValue));

                if (ringtone == null) 
                    // Clear the summary if there was a lookup error.
                    preference.setSummary(null);
                 else 
                    // Set the summary to reflect the new ringtone display
                    // name.
                    String name = ringtone
                            .getTitle(preference.getContext());
                    preference.setSummary(name);
                
            

         else 
            // For all other preferences, set the summary to the value's
            // simple string representation.
            preference.setSummary(stringValue);
        
        return true;
    
;

/**
 * Binds a preference's summary to its value. More specifically, when the
 * preference's value is changed, its summary (line of text below the
 * preference title) is updated to reflect the value. The summary is also
 * immediately updated upon calling this method. The exact display format is
 * dependent on the type of preference.
 * 
 * @see #sBindPreferenceSummaryToValueListener
 */
private static void bindPreferenceSummaryToValue(Preference preference) 
    // Set the listener to watch for value changes.
    preference
            .setOnPreferenceChangeListener(sBindPreferenceSummaryToValueListener);

    // Trigger the listener immediately with the preference's
    // current value.
    sBindPreferenceSummaryToValueListener.onPreferenceChange(
            preference,
            PreferenceManager.getDefaultSharedPreferences(
                    preference.getContext()).getString(preference.getKey(),
                    ""));


/**
 * This fragment shows general preferences only. It is used when the
 * activity is showing a two-pane settings UI.
 */
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
public static class GeneralPreferenceFragment extends PreferenceFragment 
    @Override
    public void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        addPreferencesFromResource(R.xml.pref_general);

        // Bind the summaries of EditText/List/Dialog/Ringtone preferences
        // to their values. When their values change, their summaries are
        // updated to reflect the new value, per the Android Design
        // guidelines.
        bindPreferenceSummaryToValue(findPreference("example_text"));
        bindPreferenceSummaryToValue(findPreference("example_list"));
    


/**
 * This fragment shows notification preferences only. It is used when the
 * activity is showing a two-pane settings UI.
 */
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
public static class NotificationPreferenceFragment extends
        PreferenceFragment 
    @Override
    public void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        addPreferencesFromResource(R.xml.pref_notification);

        // Bind the summaries of EditText/List/Dialog/Ringtone preferences
        // to their values. When their values change, their summaries are
        // updated to reflect the new value, per the Android Design
        // guidelines.
        bindPreferenceSummaryToValue(findPreference("notifications_new_message_ringtone"));
    


/**
 * This fragment shows data and sync preferences only. It is used when the
 * activity is showing a two-pane settings UI.
 */
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
public static class DataSyncPreferenceFragment extends PreferenceFragment 
    @Override
    public void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        addPreferencesFromResource(R.xml.pref_data_sync);

        // Bind the summaries of EditText/List/Dialog/Ringtone preferences
        // to their values. When their values change, their summaries are
        // updated to reflect the new value, per the Android Design
        // guidelines.
        bindPreferenceSummaryToValue(findPreference("sync_frequency"));
    

【问题讨论】:

你到底想要什么? 我希望识别器永远听我说,而不是 10 秒。它应该不断地听我说。应用程序将等待特定关键字的语音:当用户说出此关键字时,服务准备好接收用户语音命令。 您的代码现在是否在服务或活动中? 在活动中。我将我的代码添加到问题中。顺便感谢您的关注。 你显示谷歌语音用户界面,对于果冻豆你可以让它连续。但是如果你想要连续的语音识别,那么你必须编写自己的 UI 【参考方案1】:

在最近的 Google 搜索更新中,这些参数不再适用于 Jelly Bean 设备。一段时间以来,我一直想提交一份关于 if 的错误报告。它们仍然适用于 ICS 设备及以下设备。

如果您想在不超时的情况下继续侦听关键字,则必须执行循环,从而检查 onPartialResults 中的关键字。如果调用Results,也没有检测到关键字,则需要立即重启识别。

您需要处理silent death bug 并将系统音频流静音到prevent the Jelly Bean beep sound。

这些问题使实施变得非常混乱和令人沮丧。谷歌整理一下……

【讨论】:

【参考方案2】:

这仅适用于果冻豆

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) 
if (requestCode == REQUEST_CODE && resultCode == RESULT_OK) 
    // Populate the wordsList with the String values the recognition
    // engine thought it heard
    ArrayList<String> matches = data
            .getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS);
    wordsList.setAdapter(new ArrayAdapter<String>(this,
            android.R.layout.simple_list_item_1, matches));

else 
finishActivity(REQUEST_CODE);
          startAndroidVoiceRecognition();

super.onActivityResult(requestCode, resultCode, data);
  

public startAndroidVoiceRecognition()

    Intent intent = new Intent(
                    RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
            intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL,
                    RecognizerIntent.LANGUAGE_MODEL_FREE_FORM);
            intent.putExtra(RecognizerIntent.EXTRA_PROMPT,
                    "Voice recognition Demo...");
            String defaultLanguage = Locale
                    .getDefault().toString();
            intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, Locale
                    .getDefault());
    startActivityForResult(intent, REQUEST_CODE);

【讨论】:

我无法理解,与我的代码相比有什么区别? 你好,我也遇到了这个问题。你修了吗??

以上是关于关于语音识别的 Android 附加功能不起作用的主要内容,如果未能解决你的问题,请参考以下文章

System.Speech 语音识别不起作用

Android 语音识别将数据传回 Xamarin Forms

12-11锦上添花Flutter AI只能语音搜索功能实现

语音中的关于语音识别的一些知识

Android科大讯飞——语音识别

android如何自定义语音识别