1 简介
之前在《搜狗语音云开发入门--移动端轻松添加高大上的语音识别》中介绍了使用搜狗语音云为客户端程序添加在线语音识别服务。在线语音服务需要联网使用,但是你不能指望用户拥有完美的环境,事实上大多数情况下用户的外围环境都会有所限制。有的时候没有Wi-Fi、没有流量,还想使用语音识别,如果你给用户一个提示“您没开流量...”只能说你的程序弱爆了。有条件情况下给用户提供完美的服务,没有条件创造条件服务质量依然完美,并且清风徐来了无痕迹,这才是完美应用的体现。你不是用户的亲戚朋友同学战友,不是武藤苍井上原结衣小子玛利亚,不是黎明郭富城刘德华梁朝伟,也不是王朔海岩郭敬明韩寒,这些你统统不是。但你做的应用还是能让人喜欢用,赶都赶不走,那就是能力。不好意思扯远了。
2 提供的服务
离线语音识别服务由两部分组成:搜狗离线语音识别引擎和开发API。不能联网,语音引擎就转到你本地了。而通过调用API,可以操作离线语音识别Service,对离线语音识别Service执行start、bind和unbind等操作。还可以获取结果,通过向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>
布局中,我们放入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文档。赶快试一试吧!
版权声明:本文为博主原创文章,未经博主允许不得转载。