在Cupcake中,Android引入了對語音識別的支持。為了進(jìn)行語音識別,以語音撥號為例,在語音識別引擎中,首先要啟動麥克風(fēng),然后創(chuàng)建一個語音識別器,接著掃描電話本,查看語法分析數(shù)據(jù)庫g2g文件是否陳舊。如果陳舊,則重構(gòu)g2g文件,否則就加載g2g文件。然后啟動語音識別器,進(jìn)行語音的捕獲并等待處理結(jié)果。當(dāng)處理完成后,語音識別引擎會返回一組Intent,后停止麥克風(fēng)和語音識別器。對語音撥號的具體處理過程如下:
public void recognize(VoiceDialerActivity voiceDialerActivity,File micFile, File contactsFile, String codec)
{
InputStream mic=null;
boolean recognizerStarted=false;
try {
if (Config.LOGD) Log.d(TAG, "start");
mVoiceDialerActivity=voiceDialerActivity; //啟動voiceDialerActivity
mLogger=null;
if (RecognizerLogger.isEnabled(mVoiceDialerActivity))
{
mLogger=new RecognizerLogger(mVoiceDialerActivity);
}
if (Config.LOGD) Log.d(TAG, "start new MicrophoneInputStream");
if (micFile !=null)
{
mic=new FileInputStream(micFile); //創(chuàng)建輸入流
WaveHeader hdr=new WaveHeader(); //音頻格式為WAV
hdr.read(mic); //設(shè)置輸入設(shè)備
}
else
{
mic=new MicrophoneInputStream(SAMPLE_RATE, SAMPLE_RATE * 15);
}
voiceDialerActivity.onMicrophoneStart(); //提醒用戶輸入語音
//創(chuàng)建新識別器
if (Config.LOGD) Log.d(TAG, "start new Recognizer");
if (mSrec==null) mSrec=new Recognizer(SREC_DIR + "/baseline11k.par");
if (Config.LOGD) Log.d(TAG, "start getVoiceContacts");
List contacts=contactsFile !=null ?
VoiceContact.getVoiceContactsFromFile(contactsFile) :
VoiceContact.getVoiceContacts(mVoiceDialerActivity);
if (mLogger !=null) mLogger.logContacts(contacts);
//產(chǎn)生g2g語法文件名
File g2g=mVoiceDialerActivity.getFileStreamPath("voicedialer."+Integer.toHexString(contacts.hashCode()) + ".g2g");
//如果當(dāng)前g2g文件過期,重構(gòu)g2g文件
if (!g2g.exists())
{
deleteAllG2GFiles(mVoiceDialerActivity);
if (mSrecGrammar !=null)
{
mSrecGrammar.destroy();
mSrecGrammar=null;
}
//加載空語法器
if (Config.LOGD) Log.d(TAG, "start new Grammar");
mSrecGrammar=mSrec.new Grammar(SREC_DIR + "/grammars/VoiceDialer.g2g"); //語法分析數(shù)據(jù)庫VoiceDialer.g2g"
mSrecGrammar.setupRecognizer(); ///啟動語音識別器
if (Config.LOGD) Log.d(TAG, "start grammar.resetAllSlots");
mSrecGrammar.resetAllSlots();
addOpenEntriesToGrammar();
addNameEntriesToGrammar(contacts);
//編譯語法器
if (Config.LOGD) Log.d(TAG, "start grammar.compile");
mSrecGrammar.compile();
//更新g2g文件
if (Config.LOGD) Log.d(TAG, "start grammar.save " + g2g.getPath());
g2g.getParentFile().mkdirs();
mSrecGrammar.save(g2g.getPath());
}
else if (mSrecGrammar==null)
{
if (Config.LOGD) Log.d(TAG, "start new Grammar loading " + g2g);
mSrecGrammar=mSrec.new Grammar(g2g.getPath());
mSrecGrammar.setupRecognizer();
}
//啟動識別過程
if (Config.LOGD) Log.d(TAG, "start mSrec.start");
mSrec.start();
recognizerStarted=true;
if (mLogger !=null) mic=mLogger.logInputStream(mic, SAMPLE_RATE);
while (true) {
if (Thread.interrupted()) throw new InterruptedException();
int event=mSrec.advance();
if (event !=Recognizer.EVENT_INCOMPLETE &&event !=Recognizer.EVENT_NEED_MORE_AUDIO)
{
if (Config.LOGD) Log.d(TAG, "start advance()="+Recognizer.eventToString(event));
}
switch (event) {
case Recognizer.EVENT_INCOMPLETE:
case Recognizer.EVENT_STARTED:
case Recognizer.EVENT_START_OF_VOICING:
case Recognizer.EVENT_END_OF_VOICING:
continue;
case Recognizer.EVENT_RECOGNITION_RESULT:
onRecognitionSuccess(); //識別結(jié)果
break;
case Recognizer.EVENT_NEED_MORE_AUDIO:
mSrec.putAudio(mic); //繼續(xù)輸入語音
continue;
default:
mVoiceDialerActivity.onRecognitionFailure(Recognizer.eventToString(event));
break;
}
break;
}
}
catch (InterruptedException e)
{
if (Config.LOGD) Log.d(TAG, "start interrupted "+e);
}
catch(IOException e)
{
if (Config.LOGD) Log.d(TAG, "start new Srec failed "+e);
mVoiceDialerActivity.onRecognitionError(e.toString());
}
finally {
//停止麥克風(fēng)
try {
if (mic !=null) mic.close();
}
catch (IOException ex)
{
if (Config.LOGD) Log.d(TAG, "start - mic.close failed - " + ex);
}
mic=null;
//關(guān)閉識別器
if (Config.LOGD) Log.d(TAG, "start mSrec.stop");
if (mSrec !=null && recognizerStarted) mSrec.stop();
try {
if (mLogger !=null) mLogger.close();
}
catch (IOException ex)
{
if (Config.LOGD) Log.d(TAG, "start - mLoggger.close failed - " + ex);
}
mLogger=null;
}
if (Config.LOGD) Log.d(TAG, "start bye");
}