搜狗語音雲開發入門(二)——使用離線語音識別服務
1 簡介
之前在《搜狗語音雲開發入門--移動端輕鬆新增高大上的語音識別》中介紹了使用搜狗語音雲為客戶端程式新增線上語音識別服務。線上語音服務需要聯網使用,但是你不能指望使用者擁有完美的環境,事實上大多數情況下使用者的外圍環境都會有所限制。有的時候沒有Wi-Fi、沒有流量,還想使用語音識別,如果你給使用者一個提示“您沒開流量...”只能說你的程式弱爆了。有條件情況下給使用者提供完美的服務,沒有條件創造條件服務質量依然完美,並且清風徐來了無痕跡,這才是完美應用的體現。你不是使用者的親戚朋友同學戰友,不是武藤蒼井上原結衣小子瑪利亞,不是黎明郭富城劉德華梁朝偉,也不是王朔海巖郭敬明韓寒,這些你統統不是。但你做的應用還是能讓人喜歡用,趕都趕不走,那就是能力。不好意思扯遠了。
2 提供的服務
離線語音識別服務由兩部分組成:搜狗離線語音識別引擎和開發API。不能聯網,語音引擎就轉到你本地了。而通過呼叫API,可以操作離線語音識別Service,對離線語音識別Service執行start、bind和unbind等操作。還可以獲取結果,通過向Service發請求,獲取離線語音識別結果或者出錯資訊。
3 如何使用
3.1 使用步驟
離線語音識別服務沒有快速體驗,所以需要使用必須進行服務的常規申請。
如圖,首先點選“開發者專區”,選擇“離線識別”,然後填寫詳細的應用資訊與開發者資訊。這裡要注意的是,一定要準確填寫你的“應用包名”,否則識別有問題。
申請之後,語音雲官方會進行稽核,不過這個稽核是需要一點時間的,
稽核過程中,你隨時可以點選右上角:賬號 - 我的應用,檢視稽核結果。成功之後會有:
可以看到基本資訊列出來了,然後點選“應用資訊”:
關鍵是“appId”與“access-key”這兩項,程式呼叫的時候需要用到,記得儲存好。
3.2 呼叫服務
在呼叫服務之前,需要先將SDK服務和服務文件下載下來:
分別點選“SDK下載”中的“下載SDK”和“開發文件”,將兩份檔案下載:
將SDK壓縮檔案解壓後,裡面有一個libs資料夾,進入後可以看到裡面的檔案:
將它們放入你的Android工程的libs裡面,並在工程中將
下載搜狗離線語音識別引擎。程式中的API正是呼叫的該引擎中的服務。注意,首次使用或者使用次數達到上限時,需要進行聯網認證,其它時候離線即可提供服務。
接下來關注我們的Android工程。修改AndroidManifest.xml,需要確保app具有以下許可權:
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /><span style="font-family: 宋體; background-color: rgb(255, 255, 255);"> </span>
在Android中添加布局:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.example.testyuyinoffline.MainActivity" >
<RelativeLayout
android:id="@id/textLayout"
android:layout_width="wrap_content"
android:layout_height="wrap_content" >
<TextView
android:id="@id/statusLabel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dip"
android:layout_marginLeft="30dip"
android:layout_alignParentLeft="true"
android:text="@string/statusLabel" />
<TextView
android:id="@id/statusTextTv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dip"
android:layout_marginRight="20dip"
android:layout_alignParentRight="true"
android:text="@string/statusText" />
<TextView
android:id="@id/toSayLabelTv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dip"
android:layout_marginLeft="30dip"
android:layout_alignParentLeft="true"
android:layout_below="@id/statusLabel"
android:text="@string/toSayLabel" />
<TextView
android:id="@id/toSayTextTv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dip"
android:layout_marginRight="20dip"
android:layout_alignParentRight="true"
android:layout_below="@id/statusTextTv"
android:text="@string/toSayText" />
</RelativeLayout>
<Button
android:id="@id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="100dip"
android:layout_centerHorizontal="true"
android:text="@string/clickMe" />
</RelativeLayout>
佈局中,我們放入4個TextView,分別用來標記和顯示服務請求的狀態、識別內容,然後再放置一個按鈕,用來啟動識別服務。
下面我們來看看activity中的呼叫程式碼:
package com.example.testyuyinoffline;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.telephony.TelephonyManager;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
import com.sogou.speech.offlinelistener.OutsideCallListener;
import com.sogou.speech.offlineutility.CoreControl;
public class MainActivity extends Activity {
public static final String MSG_TEXT = "MSG_TEXT";
CoreControl coreControl;
TextView statusTextTView;
TextView toSayTextTvTextView;
Runnable regThread = new Runnable() {
@Override
public void run() {
coreControl.startListening();
}
};
Handler handler = new Handler() {
@Override
public void handleMessage(android.os.Message msg) {
System.out.println("what=" + msg.what);
switch (msg.what) {
// 1.開始識別
case 0x1:
statusTextTView.setText("開始識別!");
break;
// 2.認證成功
case 0x2:
statusTextTView.setText("認證成功,請說話!");
break;
// 3.錄音結束
case 0x3:
statusTextTView.setText("錄音結束!");
break;
// 4.說話內容
case 0x4:
String text = msg.getData().getString(MSG_TEXT);
toSayTextTvTextView.setText(text);
break;
default:
break;
}
}
};
@Override
protected void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
if (coreControl != null) {
coreControl.onDestroyService();
System.out.println("斷開語音service");
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button button = (Button) findViewById(R.id.button);
statusTextTView = (TextView) findViewById(R.id.statusTextTv);
toSayTextTvTextView = (TextView)findViewById(R.id.toSayTextTv);
coreControl = new CoreControl(this.getApplicationContext(),
(TelephonyManager) this.getSystemService(TELEPHONY_SERVICE),
"<span style="background-color: rgb(255, 0, 0);">appId</span>", "<span style="background-color: rgb(255, 0, 0);">access-key</span>");
coreControl.setmListener(new OutsideCallListener() {
@Override
public void onUpdateVolume(int arg0) {
// TODO Auto-generated method stub
}
// 3.錄音結束
@Override
public void onSpeechEnd() {
// TODO Auto-generated method stub
Bundle bundle = new Bundle();
bundle.putString(MSG_TEXT, "錄音結束");
Message msg = handler.obtainMessage();
msg.what = 0x3;
msg.setData(bundle);
msg.sendToTarget();
System.out.println("3.錄音結束");
}
@Override
public void onServiceConnected(String arg0) {
// TODO Auto-generated method stub
}
// 4.說話內容
@Override
public void onResults(String arg0, boolean arg1) {
Bundle bundle = new Bundle();
bundle.putString(MSG_TEXT, arg0);
Message msg = handler.obtainMessage();
msg.what = 0x4;
msg.setData(bundle);
msg.sendToTarget();
System.out.println("4.說話內容:" + arg0);
}
// 1.開始識別
@Override
public void onRecognitionStart() {
Bundle bundle = new Bundle();
bundle.putString(MSG_TEXT, "開始識別!");
Message msg = handler.obtainMessage();
msg.what = 0x1;
msg.setData(bundle);
msg.sendToTarget();
System.out.println("1.開始識別!");
}
// 2.認證成功
@Override
public void onPassedValidation() {
Bundle bundle = new Bundle();
bundle.putString(MSG_TEXT, "認證成功!");
Message msg = handler.obtainMessage();
msg.what = 0x2;
msg.setData(bundle);
msg.sendToTarget();
System.out.println("2.認證成功,請說話!");
}
@Override
public void onFinishInit() {
// TODO Auto-generated method stub
}
@Override
public void onError(int arg0) {
System.err.println("錯誤程式碼:" + arg0);
}
});
coreControl.onInitializeService();
button.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if (coreControl != null) {
// coreControl.startListening();
handler.post(regThread);
}
}
});
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
}
注意將其中的“appId”和“access-key”換成你申請下來的資訊值。
我們的思路是,點選按鈕的時候,啟動語音識別服務;語音識別的不同狀態過程中,將狀態情況顯示在介面上;識別出說話內容之後,將內容顯示在介面上。
在activity中,建立一個執行緒,執行緒開啟識別服務。
在程式建立的過程中,首先新建一個CoreControl物件,將程式環境資訊、appId、access-key等傳進去。然後給CoreControl物件設定OutsideCallListener監聽。監聽中有幾個比較重要的回撥函式:
1.開始識別
public void onRecognitionStart()
2.認證成功
public void onPassedValidation()
3.錄音結束
public void onSpeechEnd()
4.得到說話內容
public void onResults(String arg0, boolean arg1)
在這幾個回撥函式中,均使用handler向主執行緒傳遞狀態引數。主執行緒的handler在其:
public void handleMessage(android.os.Message msg)
這個函式中更改介面狀態,並將識別內容顯示出來。當退出App時,呼叫onDestroyService()方法斷開與Service的連線:
protected void onDestroy()
在出現異常的回撥函式中:
public void onError(int arg0)
可以錯誤碼列印到後臺或返回到前端,以便分析錯誤種類。錯誤碼定義:
很簡單不是嗎!
3.3 客戶端使用
啟動後介面:
點選“我要說話”:
對著麥克風說話後:
更詳細的內容可以參考搜狗的示例程式及SDK文件。趕快試一試吧!