轉載請注明CSDN博文位址:http://blog.csdn.net/ls0609/article/details/71519203
語音記賬demo:http://blog.csdn.net/ls0609/article/details/72765789
olami sdk實作了把錄音或者文字轉化為使用者可以了解的json字元串進而實作語義了解,使用者可以定義自己的語義,是不是很強大?本文講述怎麼自定義語義,以及如何解析自定義語義。
本文使用olami sdk做了一個線上聽書的demo,使用者隻需類似“我想聽***”就能實作聽書的線上查找并播放。用的是喜馬拉雅的線上聽書sdk.基于eclipse開發環境,libs目錄下jar和so檔案如下:
olami-android-sdk.jar //olami sdk 的jar
afinal_0.5.1_bin.jar
litepal.jar
gson-2.2.4.jar
okhttp-2.4.0.jar
okhttp-urlconnection-2.2.0.jar
okio-1.4.0.jar
opensdk.jar //上面這幾個都是喜馬拉雅需要的jar
libspeex.so //olami sdk 需要用到speex壓縮功能
libxmediaplayer.so // 喜馬拉雅so
libxmediaplayer_x.so // 喜馬拉雅so
概述:
VoiceSdkService中定義了OlamiVoiceRecognizer語音識别引擎,通過點選MusicActivity的開始button啟動錄音,錄音結果在VoiceSdkService中的onResult()回調中拿到識别的Json字元串,在processServiceMessage()函數中處理後找到要聽書的名稱,然後進入BookUtil進行搜尋,搜尋到結果後通知VoiceSdkService進行播放,并通知MusicActivity更新播放進度等資訊。
1.AndroidManifest.xml配置
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.olami.musicdemo"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="21" />
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<application
android:name="com.olami.musicdemo.OlamiApplication"
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<!--喜馬拉雅聽書測試賬号app_key-->
<meta-data
android:name="app_key"
android:value="b617866c20482d133d5de66fceb37da3" />
<!--喜馬拉雅聽書測試賬号包名-->
<meta-data
android:name="pack_id"
android:value="com.app.test.android" />
<activity
android:name=".MusicActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<!--注冊olami sdk service-->
<service
android:name=".VoiceSdkService"
android:exported="true" >
</service>
<!--注冊喜馬拉雅聽書service-->
<service
android:name=
"com.ximalaya.ting.android.opensdk.player.service.XmPlayerService"
/>
</application>
</manifest>
2.layout布局檔案
layout_musicview.xml
TextView 有兩個,tv_name顯示聽書的名稱, tv_totoal_time顯示聽書的總時間。
ProgressBar 實時重新整理顯示聽書的進度
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="@android:color/transparent">
<TextView
android:text="name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:layout_centerHorizontal="true"
android:id="@+id/tv_name"/>
<ProgressBar
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/tv_name"
android:layout_marginTop="10dp"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
android:id="@+id/progressbar_music"/>
<TextView
android:text="total_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/progressbar_music"
android:layout_marginTop="10dp"
android:layout_centerHorizontal="true"
android:id="@+id/tv_total_time"/>
</RelativeLayout>
activity_music.xml
<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:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
tools:context="com.olami.musicdemo.MusicActivity" >
<TextView
android:id="@+id/tv_inputText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:text="輸入:" />
<TextView
android:id="@+id/tv_volume"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="@+id/tv_inputText"
android:layout_below="@+id/tv_inputText"
android:layout_marginTop="40dp"
android:text="音量:" />
<TextView
android:id="@+id/tv_result"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/tv_volume"
android:layout_marginTop="20dp"
android:maxLines="15"
android:ellipsize="end"
android:text="伺服器傳回sentence:"
android:visibility="visible" />
<com.olami.musicdemo.MusicView
android:id="@+id/music_view"
android:layout_width="fill_parent"
android:layout_height="80dp"
android:layout_centerInParent="true"
>
</com.olami.musicdemo.MusicView>
<EditText
android:id="@+id/et_content"
android:layout_width="wrap_content"
android:layout_height="40dp"
android:layout_above="@+id/btn_stop"
android:layout_alignLeft="@+id/tv_inputText"
android:layout_marginBottom="10dp"
android:layout_toLeftOf="@+id/btn_send"
android:background="#E7E7E7"
android:singleLine="true"
android:text="上海的天氣" />
<Button
android:id="@+id/btn_send"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBaseline="@+id/et_content"
android:layout_alignBottom="@+id/et_content"
android:layout_alignParentRight="true"
android:text="送出" />
<Button
android:id="@+id/btn_start"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:text="開始" />
<Button
android:id="@+id/btn_stop"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="@+id/et_content"
android:layout_alignParentBottom="true"
android:text="停止" />
<Button
android:id="@+id/btn_cancel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_toRightOf="@+id/et_content"
android:text="取消" />
</RelativeLayout>
自定義MusicView比較簡單,代碼如下:
public class MusicView extends RelativeLayout{
private Context mContext;
private Handler mHandler;
private TextView mTextViewName;
private TextView mTextViewTotalTime;
private ProgressBar mProgressBar;
public MusicView(Context context,AttributeSet attrs) {
super(context,attrs);
LayoutInflater inflater =(LayoutInflater) context.getSystemService(
context.LAYOUT_INFLATER_SERVICE);
RelativeLayout view = (RelativeLayout) inflater.inflate(R.layout.layout_musicview, this,true);
mTextViewName = (TextView) view.findViewById(R.id.tv_name);
mTextViewTotalTime = (TextView) view.findViewById(R.id.tv_total_time);
mProgressBar = (ProgressBar)view.findViewById(R.id.progressbar_music);
}
public void initMusicView(Context context,Handler handler)
{
mContext = context;
mHandler = handler;
}
public void setMusicName(String name)
{//設定播放名稱
mTextViewName.setText(name);
}
public void setProgress(int progress)
{//設定播放進度
mProgressBar.setProgress(progress);
}
public void setTotalTime(String time)
{//設定播放總時間
mTextViewTotalTime.setText(time);
}
}
布局效果圖如下:

3.MusicActivity和VoiceSdkService通信
本文沒有用bind service的方式實作activity和service的消息通信。
MusicAcitity 和 VoiceSdkService中分别實作了一個CommunicationAssist的接口
public interface CommunicationAssist {
public void callBack(int what, int arg1, int arg2,Bundle data, Object obj);
}
然後把他們分别實作CommunicationAssist接口的變量注冊到OlamiApplication,這樣通過OlamiApplication實作了MusicAcitity 和 VoiceSdkService橋接。
3.1OlamiApplication
1) 注冊MusicActivity到VoiceSdkService的回調
public void setActivityToServiceListener(CommunicationAssist listener)
{
ActivityToServiceListener = listener;
}
這個是在VoiceSdkService中調用setActivityToServiceListener(),把VoiceSdkService中的VoiceSdkComAssist注冊到application中,MusicActivity中可以通過getActivityToServiceListener
這個函數回調向VoiceSdkService發送消息。
2) 注冊 VoiceSdkService到MusicActivity回調
public void setServiceToActivityListener(CommunicationAssist listener)
{
mServiceToActivityListener = listener;
}
這個是在MusicAcitivity中調用setServiceToActivityListener(),這樣在VoiceSdkService中就可以通過getServiceToActivityListener()獲得回調向MusciActivity發送消息。
3.2 MusicActivity
public class MusicActivity extends Activity {
private Handler mHandler;
private Handler mInComingHandler;
private ActivityComAssist mActivityComAssist;
private Button mBtnStart;
private Button mBtnStop;
private Button mBtnCancel;
private Button mBtnSend;
private EditText mEditText;
private TextView mTextView;
private TextView mInputTextView;
private TextView mTextViewVolume;
private BookUtil mBookUtil = null;
private MusicView mMusicView = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_music);
initHandler();//初始化handler用于内部消息處理
initInComingHandler();//用于處理來自VoiceSdkService的消息
initCommunicationAssist();//向application注冊消息回調,VoiceSdkSerive可以
//通過getServiceToActivityListener()獲得回調向MusicActivity發送消息
initView();//初始化view控件
Intent intent = new Intent();
intent.setClass(MusicActivity.this, VoiceSdkService.class);
startService(intent);//啟動背景服務
}
private void initView()
{
mBtnStart = (Button) findViewById(R.id.btn_start);
mBtnStop = (Button) findViewById(R.id.btn_stop);
mBtnCancel = (Button) findViewById(R.id.btn_cancel);
mBtnSend = (Button) findViewById(R.id.btn_send);
mInputTextView = (TextView) findViewById(R.id.tv_inputText);
mEditText = (EditText) findViewById(R.id.et_content);
mTextView = (TextView) findViewById(R.id.tv_result);
mTextViewVolume = (TextView) findViewById(R.id.tv_volume);
mBtnStart.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View v) {
sendMessageToService(MessageConst.CLIENT_ACTION_START_RECORED,,,null,null);
}
});
mBtnStop.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View v) {
sendMessageToService(MessageConst.CLIENT_ACTION_STOP_RECORED,,,null,null);
mBtnStart.setText("開始");
Log.i("led","MusicActivity mBtnStop onclick 開始");
}
});
mBtnCancel.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View v) {
sendMessageToService(MessageConst.CLIENT_ACTION_CANCEL_RECORED,,,null,null);
}
});
mBtnSend.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View v) {
sendMessageToService(
MessageConst.CLIENT_ACTION_SENT_TEXT,,,null,mEditText.getText());
mInputTextView.setText("文字: "+mEditText.getText());
}
});
mMusicView = (MusicView) findViewById(R.id.music_view);
//if(mMusicView != null)
//mMusicView.initMusicView(MusicActivity.this,mHandler);
}
private void initHandler()
{
mHandler = new Handler(){
@Override
public void handleMessage(Message msg)
{
switch (msg.what){
case MessageConst.CLIENT_ACTION_START_RECORED:
break;
default:
break;
}
}
};
}
//InComingHandler 收到來自VoiceSdkService的消息用于更新界面,
//包括開始錄音,結束錄音,播放的書的名稱和進度,音量等資訊。
private void initInComingHandler()
{
mInComingHandler = new Handler(){
@Override
public void handleMessage(Message msg)
{
switch (msg.what){
case MessageConst.CLIENT_ACTION_START_RECORED:
mBtnStart.setText("錄音中");
Log.i("led","MusicActivity 錄音中");
break;
case MessageConst.CLIENT_ACTION_STOP_RECORED:
mBtnStart.setText("識别中");
Log.i("led","MusicActivity 識别中");
break;
case MessageConst.CLIENT_ACTION_CANCEL_RECORED:
mBtnStart.setText("開始");
mTextView.setText("已取消");
break;
case MessageConst.CLIENT_ACTION_ON_ERROR:
mTextView.setText("錯誤代碼:"+msg.arg1);
mBtnStart.setText("開始");
break;
case MessageConst.CLIENT_ACTION_UPDATA_VOLUME:
mTextViewVolume.setText("音量: "+msg.arg1);
break;
case MessageConst.SERVER_ACTION_RETURN_RESULT:
//mTextView.setText(msg.obj.toString());
mBtnStart.setText("開始");
break;
case MessageConst.CLIENT_ACTION_PLAY_BOOK_AFTER_SEARCH:
mBtnStart.setText("開始");
mBookUtil = BookUtil.getInstance();
mBookUtil.play(msg.arg1);
break;
case MessageConst.CLIENT_ACTION_UPDATA_PLAYING_BOOK_NAME:
mMusicView.setMusicName(msg.obj.toString());
break;
case MessageConst.CLIENT_ACTION_UPDATE_BOOK_PROGRESS:
int current = msg.arg1;
int duration = msg.arg2;
mMusicView.setProgress(current*/duration);
float time = duration//;
mMusicView.setTotalTime("總時間:"+time);
break;
case MessageConst.CLIENT_ACTION_UPDATA_INPUT_TEXT:
if(msg.obj != null)
mInputTextView.setText("文字: "+msg.obj.toString());
break;
case MessageConst.CLIENT_ACTION_UPDATA_SERVER_MESSAGE:
if(msg.obj != null)
mTextView.setText("伺服器傳回sentence: "+msg.obj.toString());
break;
default:
break;
}
}
};
}
private void initCommunicationAssist()
{//向Application注冊VoiceSdkService到MusicActivity的回調
mActivityComAssist = new ActivityComAssist();
OlamiApplication.getInstance().setServiceToActivityListener(mActivityComAssist);
}
private void sendMessageToService(int what, int arg1, int arg2, Bundle data, Object obj)
{//向VoiceSdkService發送消息
if(OlamiApplication.getInstance().getActivityToServiceListener() != null)
OlamiApplication.getInstance().getActivityToServiceListener().callBack
(what, arg1, arg2, data, obj);
}
private class ActivityComAssist implements CommunicationAssist{
//實作CommunicationAssist借口,用于回調VoiceSdkService發送過來的消息
@Override
public void callBack(int what, int arg1, int arg2, Bundle data,Object obj) {
Message msg = Message.obtain(null, what);
msg.arg1 = arg1;
msg.arg2 = arg2;
if (data != null)
msg.setData(data);
if (obj != null)
msg.obj = obj;
mInComingHandler.sendMessage(msg);
}
}
@Override
public void onDestroy() {
//退出應用,停止VoiceSdkService,會進行資源的釋放
super.onDestroy();
Intent intent = new Intent();
intent.setClass(MusicActivity.this, VoiceSdkService.class);
stopService(intent);
}
}
3.3 VoiceSdkService
@Override
public void onCreate() {
initHandler();//用于内部消息處理
initInComingHandler();//用于處理來自MusicActivity的消息
initCommunicationAssist();//向application注冊消息回調,這樣MusicActivity可
//以通過getActivityToServiceListener()回調向VoiceSdkService發送消息
initViaVoiceRecognizerListener();//初始化錄音識别回調listener
init();//olami錄音識别引擎初始化
initXmly();//喜馬拉雅初始化
}
public void init()
{
initHandler();
mOlamiVoiceRecognizer = new OlamiVoiceRecognizer(VoiceSdkService.this);
TelephonyManager telephonyManager=(TelephonyManager) this.getSystemService(
(this.getBaseContext().TELEPHONY_SERVICE);
String imei=telephonyManager.getDeviceId();
mOlamiVoiceRecognizer.init(imei);//設定身份辨別,可以填null
mOlamiVoiceRecognizer.setListener(mOlamiVoiceRecognizerListener);//設定識别結果回調listener
mOlamiVoiceRecognizer.setLocalization(
OlamiVoiceRecognizer.LANGUAGE_SIMPLIFIED_CHINESE);//設定支援的語音類型,優先選擇中文簡體
mOlamiVoiceRecognizer.setAuthorization("51a4bb56ba954655a4fc834bfdc46af1",
"asr","68bff251789b426896e70e888f919a6d","nli");
//注冊Appkey,在olami官網注冊應用後生成的appkey
//注冊api,請直接填寫“asr”,辨別語音識别類型
//注冊secret,在olami官網注冊應用後生成的secret
//注冊seq ,請填寫“nli”
mOlamiVoiceRecognizer.setVADTailTimeout();//錄音時尾音結束時間,建議填//2000ms
//設定經緯度資訊,不願上傳位置資訊,可以填0
mOlamiVoiceRecognizer.setLatitudeAndLongitude(,);
}
定義OlamiVoiceRecognizerListener
onError(int errCode)//出錯回調,可以對比官方文檔錯誤碼看是什麼錯誤
onEndOfSpeech()//錄音結束
onBeginningOfSpeech()//錄音開始
onResult(String result, int type)//result是識别結果JSON字元串
onCancel()//取消識别,不會再傳回識别結果
onUpdateVolume(int volume)//錄音時的音量,1-12個級别大小音量
下面是VoiceSdkService完整代碼:
public class VoiceSdkService extends Service{
private Handler mHandler;
private Handler mInComingHandler;
private VoiceSdkComAssist mVoiceSdkComAssist;
private OlamiVoiceRecognizer mOlamiVoiceRecognizer;
private OlamiVoiceRecognizerListener mOlamiVoiceRecognizerListener;
private BookUtil mBookUtil = null;
private boolean mIsRecordPause = false;
@Override
public void onCreate() {
initHandler();
initInComingHandler();
initCommunicationAssist();
initViaVoiceRecognizerListener();
init();
initXmly();
}
@Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}
public void init()
{
initHandler();
mOlamiVoiceRecognizer = new OlamiVoiceRecognizer(VoiceSdkService.this);
TelephonyManager telephonyManager=(TelephonyManager) this.getSystemService(
this.getBaseContext().TELEPHONY_SERVICE);
String imei=telephonyManager.getDeviceId();
mOlamiVoiceRecognizer.init(imei);//set null if you do not want to notify olami server.
mOlamiVoiceRecognizer.setListener(mOlamiVoiceRecognizerListener);
mOlamiVoiceRecognizer.setLocalization(
OlamiVoiceRecognizer.LANGUAGE_SIMPLIFIED_CHINESE);
mOlamiVoiceRecognizer.setAuthorization(
"51a4bb56ba954655a4fc834bfdc46af1",
"asr","68bff251789b426896e70e888f919a6d","nli");
mOlamiVoiceRecognizer.setVADTailTimeout();
mOlamiVoiceRecognizer.setLatitudeAndLongitude(,);
}
private void initHandler()
{
mHandler = new Handler(){
@Override
public void handleMessage(Message msg)
{
switch (msg.what){
case MessageConst.CLIENT_ACTION_START_RECORED:
sendMessageToActivity(MessageConst.CLIENT_ACTION_START_RECORED,,,null,null);
break;
case MessageConst.CLIENT_ACTION_STOP_RECORED:
sendMessageToActivity(MessageConst.CLIENT_ACTION_STOP_RECORED,,,null,null);
break;
case MessageConst.CLIENT_ACTION_ON_ERROR:
sendMessageToActivity(MessageConst.CLIENT_ACTION_ON_ERROR,msg.arg1,,null,null);
break;
case MessageConst.CLIENT_ACTION_PLAY_BOOK_AFTER_SEARCH:
sendMessageToActivity(MessageConst.
CLIENT_ACTION_PLAY_BOOK_AFTER_SEARCH, msg.arg1, , null, msg.obj);
break;
case MessageConst.CLIENT_ACTION_UPDATA_PLAYING_BOOK_NAME:
sendMessageToActivity(MessageConst.
CLIENT_ACTION_UPDATA_PLAYING_BOOK_NAME, msg.arg1, , null, msg.obj);
break;
case MessageConst.CLIENT_ACTION_UPDATE_BOOK_PROGRESS:
sendMessageToActivity(MessageConst.
CLIENT_ACTION_UPDATE_BOOK_PROGRESS, msg.arg1, msg.arg2, null, null);
break;
case MessageConst.CLIENT_ACTION_CANCEL_RECORED:
sendMessageToActivity(MessageConst.
CLIENT_ACTION_CANCEL_RECORED, msg.arg1, msg.arg2, null, null);
break;
default:
break;
}
}
};
}
private void initInComingHandler()
{
mInComingHandler = new Handler(){
@Override
public void handleMessage(Message msg)
{
switch (msg.what){
case MessageConst.CLIENT_ACTION_START_RECORED:
if(mOlamiVoiceRecognizer != null)
mOlamiVoiceRecognizer.start();
break;
case MessageConst.CLIENT_ACTION_STOP_RECORED:
if(mOlamiVoiceRecognizer != null)
mOlamiVoiceRecognizer.stop();
break;
case MessageConst.CLIENT_ACTION_CANCEL_RECORED:
if(mOlamiVoiceRecognizer != null)
mOlamiVoiceRecognizer.cancel();
break;
case MessageConst.CLIENT_ACTION_SENT_TEXT:
if(mOlamiVoiceRecognizer != null)
mOlamiVoiceRecognizer.sendText(msg.obj.toString());
break;
}
}
};
}
private void initViaVoiceRecognizerListener()
{
mOlamiVoiceRecognizerListener = new OlamiVoiceRecognizerListener();
}
private class OlamiVoiceRecognizerListener implements IOlamiVoiceRecognizerListener{
@Override
public void onError(int errCode) {
mHandler.sendMessage(mHandler.obtainMessage(
MessageConst.CLIENT_ACTION_ON_ERROR,errCode,));
}
@Override
public void onEndOfSpeech() {
mHandler.sendEmptyMessage(MessageConst.CLIENT_ACTION_STOP_RECORED);
if(mIsRecordPause)
{
mIsRecordPause = false;
mBookUtil.resumePlay();
}
}
@Override
public void onBeginningOfSpeech() {
if(mBookUtil.isPlaying())
{
mBookUtil.pause();
mIsRecordPause = true;
}
mHandler.sendEmptyMessage(MessageConst.CLIENT_ACTION_START_RECORED);
}
@Override
public void onResult(String result, int type) {
sendMessageToActivity(MessageConst.SERVER_ACTION_RETURN_RESULT,type,,null,result);
processServiceMessage(result);
}
@Override
public void onCancel() {
mHandler.sendEmptyMessage(MessageConst.CLIENT_ACTION_CANCEL_RECORED);
}
@Override
public void onUpdateVolume(int volume) {
sendMessageToActivity(MessageConst.CLIENT_ACTION_UPDATA_VOLUME,volume,,null,null);
}
}
private void initCommunicationAssist()
{
mVoiceSdkComAssist = new VoiceSdkComAssist();
OlamiApplication.getInstance().setActivityToServiceListener(mVoiceSdkComAssist);
}
private void initXmly()
{
if(mBookUtil == null)
{
mBookUtil = BookUtil.getInstance();
mBookUtil.init(VoiceSdkService.this);
mBookUtil.setHandler(mHandler);
}
}
private void processServiceMessage(String message)
{
String input = null;
String serverMessage = null;
try{
JSONObject jsonObject = new JSONObject(message);
JSONArray jArrayNli = jsonObject.optJSONObject("data").optJSONArray("nli");
JSONObject jObj = jArrayNli.optJSONObject();
JSONArray jArraySemantic = null;
if(message.contains("semantic"))
jArraySemantic = jObj.getJSONArray("semantic");
else{
input = jsonObject.optJSONObject("data").optJSONObject("asr").
optString("result");
sendMessageToActivity(MessageConst.
CLIENT_ACTION_UPDATA_INPUT_TEXT, , , null, input);
serverMessage = jObj.optJSONObject("desc_obj").opt("result").toString();
sendMessageToActivity(MessageConst.
CLIENT_ACTION_UPDATA_SERVER_MESSAGE, , , null, serverMessage);
return;
}
JSONObject jObjSemantic;
JSONArray jArraySlots;
JSONArray jArrayModifier;
String type = null;
String songName = null;
String singer = null;
if(jObj != null) {
type = jObj.optString("type");
if("musiccontrol".equals(type))
{
jObjSemantic = jArraySemantic.optJSONObject();
input = jObjSemantic.optString("input");
jArraySlots = jObjSemantic.optJSONArray("slots");
jArrayModifier = jObjSemantic.optJSONArray("modifier");
String modifier = (String)jArrayModifier.opt();
if((jArrayModifier != null) && ("play".equals(modifier)))
{
if(jArraySlots != null)
for(int i=,k=jArraySlots.length(); i<k; i++)
{
JSONObject obj = jArraySlots.getJSONObject(i);
String name = obj.optString("name");
if("singer".equals(name))
singer = obj.optString("value");
else if("songname".equals(name))
songName = obj.optString("value");
}
}else if((modifier != null) && ("stop".equals(modifier)))
{
if(mBookUtil != null)
if(mBookUtil.isPlaying())
mBookUtil.stop();
}else if((modifier != null) && ("pause".equals(modifier)))
{
if(mBookUtil != null)
if(mBookUtil.isPlaying())
mBookUtil.pause();
}else if((modifier != null) && ("resume_play".equals(modifier)))
{
if(mBookUtil != null)
mBookUtil.resumePlay();
}else if((modifier != null) && ("add_volume".equals(modifier)))
{
if(mBookUtil != null)
mBookUtil.addVolume();
}else if((modifier != null) && ("del_volume".equals(modifier)))
{
if(mBookUtil != null)
mBookUtil.delVolume();
}else if((modifier != null) && ("next".equals(modifier)))
{
if(mBookUtil != null)
mBookUtil.next();
}else if((modifier != null) && ("previous".equals(modifier)))
{
if(mBookUtil != null)
mBookUtil.prev();
}else if((modifier != null) && ("play_index".equals(modifier)))
{
int position = ;
if(jArraySlots != null)
for(int i=,k=jArraySlots.length(); i<k; i++)
{
JSONObject obj = jArraySlots.getJSONObject(i);
JSONObject jNumDetial = obj.getJSONObject("num_detail");
String index = jNumDetial.optString("recommend_value");
position = Integer.parseInt(index) - ;
}
if(mBookUtil != null)
mBookUtil.skipTo(position);
}
}
}
if(songName != null)
{
if(singer != null)
{
}else{
mBookUtil.searchBookAndPlay(songName,,);
}
}else if(singer != null)
{
mBookUtil.searchBookAndPlay(songName,,);
}
serverMessage = jObj.optJSONObject("desc_obj").opt("result").toString();
}
catch (Exception e)
{
e.printStackTrace();
}
//發送消息更新語音識别的文字
sendMessageToActivity(MessageConst.CLIENT_ACTION_UPDATA_INPUT_TEXT, , , null, input);
//發送消息更新伺服器傳回的結果字元串
sendMessageToActivity(MessageConst.CLIENT_ACTION_UPDATA_SERVER_MESSAGE,
, , null, serverMessage);
}
private void sendMessageToActivity(int what, int arg1, int arg2, Bundle data, Object obj)
{
if(OlamiApplication.getInstance().getServiceToActivityListener() != null)
OlamiApplication.getInstance().getServiceToActivityListener().
callBack(what, arg1, arg2, data, obj);
}
private class VoiceSdkComAssist implements CommunicationAssist{
@Override
public void callBack(int what, int arg1, int arg2, Bundle data,Object obj) {
Message msg = Message.obtain(null, what);
msg.arg1 = arg1;
msg.arg2 = arg2;
if (data != null)
msg.setData(data);
if (obj != null)
msg.obj = obj;
mInComingHandler.sendMessage(msg);
}
}
@Override
public void onDestroy(){
super.onDestroy();
if(mOlamiVoiceRecognizer != null)
mOlamiVoiceRecognizer.destroy();
if(mBookUtil != null)
{
mBookUtil.destroy();
}
}
}
3.4 VoiceSdkService中onResult的回調處理
在VoiceSdkService.java中processServiceMessage(String message)用于處理onResult的回調資料。例如“我要聽三國演義”傳回如下資料:
{
"data": {
"asr": {
"result": "我要聽三國演義",
"speech_status": ,
"final": true,
"status":
},
"nli": [
{
"desc_obj": {
"result": "正在努力搜尋中,請稍等",
"status":
},
"semantic": [
{
"app": "musiccontrol",
"input": "我要聽三國演義",
"slots": [
{
"name": "songname",
"value": "三國演義" }
],
"modifier": [
"play"
],
"customer": "58df512384ae11f0bb7b487e"
}
],
"type": "musiccontrol"
}
]
},
"status": "ok"
}
1)解析出nli中type類型是musiccontrol,這是文法傳回app的類型,而這個線上聽書的demo隻關心musiccontrol這 個app類型,其他的忽略。
2)使用者說的話轉成文字是在asr中的result中擷取
3)在nli中的semantic中,input值是使用者說的話,同asr中的result。
modifier代表傳回的行為動作,此處可以看到是play就是要求播放,slots中的資料表示歌曲名稱是三國演義。
那麼動作是play,内容是歌曲名稱是三國演義,在這個demo中調用
mBookUtil.searchBookAndPlay(songName,0,0);會先查詢,查詢到結果會再發播放消息要求播放,我要聽三國演義這個流程就走完了。
4.BookUtil
說一下搜尋聽書的實作過程
public void searchBookInfo(String bookName,final int index,final boolean isNeedPlay)
{
mBookName = bookName;
Map<String, String> param = new HashMap<String, String>();
param.put(DTransferConstants.SEARCH_KEY, bookName);
param.put(DTransferConstants.CATEGORY_ID, "" + );//此處3代表搜尋的是聽書
//param.put(DTransferConstants.PAGE, "" + mPageId);
param.put(DTransferConstants.SORT, "asc");//傳回清單的排序是正序還是逆序
param.put(DTransferConstants.PAGE_SIZE, "" + PAGE_SIZE);//每頁能傳回多少個查詢結果
mPage = (index/PAGE_SIZE)+;//目前在第幾頁
mPlayerManager = XmPlayerManager.getInstance(mContext);//喜馬拉雅初始化部分
mPlayerManager.init(mNotificationId, null);
mPlayerManager.addPlayerStatusListener(mPlayerStatusListener);
mPlayerManager.addAdsStatusListener(mAdsListener);
CommonRequest.getSearchedAlbums(param, new IDataCallBack<SearchAlbumList>()
{
@Override
public void onSuccess(SearchAlbumList object)
{
if (object != null && object.getAlbums() != null
&& object.getAlbums().size() != )
{
if (mSearchAlbumList == null)
{
mSearchAlbumList = object;
}
else
{
mSearchAlbumList.getAlbums().addAll(object.getAlbums());
}
//mTrackAdapter.notifyDataSetChanged();
Map<String, String> map = new HashMap<String, String>();
map.put(
DTransferConstants.ALBUM_ID, ""+object.getAlbums().get().getId());
map.put(DTransferConstants.SORT, "asc");
map.put(DTransferConstants.PAGE, "" + mPage);
map.put(DTransferConstants.PAGE_SIZE, "" + PAGE_SIZE);
CommonRequest.getTracks(map, new IDataCallBack<TrackList>()
{
@Override
public void onSuccess(TrackList object)
{
mTrackList = object;
mTotalCount = mTrackList.getTotalCount();
if(mTrackList.getTracks().size() <= )
return;
String str = "專輯:"+mTrackList.getAlbumTitle()+
get().getTrackTitle().toString();
if(isNeedPlay)
{
mPosition = index % PAGE_SIZE;
mHandler.sendMessage(mHandler.obtainMessage(
MessageConst.CLIENT_ACTION_PLAY_BOOK_AFTER_SEARCH,
index % PAGE_SIZE,));//此處mTrackList中已經查詢出結果
//向VoiceSdkService發送消息進行播放
}
else
sendBookInfoToServer();
}
@Override
public void onError(int code, String message)
{
Log.i("ppp","error: "+message);
sendBookInfoToServer();
}
});
}
}
@Override
public void onError(int code, String message)
{
Log.i("ppp","error: "+message);
sendBookInfoToServer();
}
});
}
5.demo中支援的說法
我想聽西遊記
我要聽西遊記
播放西遊記
聽西遊記
我想聽西遊記這本書
上一首
上一回
下一首
下一回
暫停/暫停播放
繼續/繼續播放
聲音大一點
聲音小一點
關閉/關閉播放
用的是喜馬拉雅測試賬号,隻支援聽書的功能,查找歌曲的結果傳回為空。
6.源碼下載下傳連結
用olamisdk語音識别引擎做線上聽書demo
7.相關連結
語音記賬demo:http://blog.csdn.net/ls0609/article/details/72765789
olami開放平台文法編寫簡介:http://blog.csdn.net/ls0609/article/details/71624340
olami開放平台文法官方介紹:https://cn.olami.ai/wiki/?mp=nli&content=nli2.html