1. 程式人生 > >搜狗語音雲開發入門(二)——使用離線語音識別服務

搜狗語音雲開發入門(二)——使用離線語音識別服務

1 簡介

之前在《搜狗語音雲開發入門--移動端輕鬆新增高大上的語音識別》中介紹了使用搜狗語音雲為客戶端程式新增線上語音識別服務。線上語音服務需要聯網使用,但是你不能指望使用者擁有完美的環境,事實上大多數情況下使用者的外圍環境都會有所限制。有的時候沒有Wi-Fi、沒有流量,還想使用語音識別,如果你給使用者一個提示“您沒開流量...”只能說你的程式弱爆了。有條件情況下給使用者提供完美的服務,沒有條件創造條件服務質量依然完美,並且清風徐來了無痕跡,這才是完美應用的體現。你不是使用者的親戚朋友同學戰友,不是武藤蒼井上原結衣小子瑪利亞,不是黎明郭富城劉德華梁朝偉,也不是王朔海巖郭敬明韓寒,這些你統統不是。但你做的應用還是能讓人喜歡用,趕都趕不走,那就是能力。不好意思扯遠了。

2 提供的服務

離線語音識別服務由兩部分組成搜狗離線語音識別引擎和開發API。不能聯網,語音引擎就轉到你本地了。而通過呼叫API,可以操作離線語音識別Service,對離線語音識別Service執行startbindunbind等操作。還可以獲取結果,通過向Service發請求,獲取離線語音識別結果或者出錯資訊。

3 如何使用

3.1 使用步驟

離線語音識別服務沒有快速體驗,所以需要使用必須進行服務的常規申請


    如圖,首先點選“開發者專區”,選擇“離線識別”,然後填寫詳細的應用資訊與開發者資訊。這裡要注意的是,一定要準確填寫你的“應用包名”,否則識別有問題。

申請之後,語音雲官方會進行稽核,不過這個稽核是需要一點時間的,

一般是4天左右。有需要的朋友們,還等什麼,趕快先申請著再說!

稽核過程中,你隨時可以點選右上角:賬號 我的應用,檢視稽核結果。成功之後會有:

    

可以看到基本資訊列出來了,然後點選“應用資訊”:

關鍵是“appId”“access-key”這兩項,程式呼叫的時候需要用到,記得儲存好。

3.2 呼叫服務

在呼叫服務之前,需要先將SDK服務和服務文件下載下來:

    

分別點選“SDK下載”中的“下載SDK”和“開發文件”,將兩份檔案下載:

將SDK壓縮檔案解壓後,裡面有一個libs資料夾,進入後可以看到裡面的檔案:

將它們放入你的Android工程的libs裡面,並在工程中將

sogou-speechapi-offline-v1.0.jar引入Build Path

下載搜狗離線語音識別引擎。程式中的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>
佈局中,我們放入4TextView,分別用來標記和顯示服務請求的狀態、識別內容,然後再放置一個按鈕,用來啟動識別服務。

下面我們來看看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物件,將程式環境資訊、appIdaccess-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文件。趕快試一試吧!