語音識別,語義理解一站式解決(android平臺&olami sdk)

轉載請注明CSDN博文地址:http://blog.csdn.net/ls0609/article/details/71519203

語音記賬demo:http://blog.csdn.net/ls0609/article/details/72765789

olami sdk語音識別語義理解做在線聽書

olamisdk實現了把錄音或者文字轉化為用戶可以理解的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配置


package="com.olami.musicdemo"

android:versionCode="1"

android:versionName="1.0" >

android:minSdkVersion="8"

android:targetSdkVersion="21" />

android:name="com.olami.musicdemo.OlamiApplication"

android:allowBackup="true"

android:icon="@drawable/ic_launcher"

android:label="@string/app_name"

android:theme="@style/AppTheme" >


android:name="app_key"

android:value="b617866c20482d133d5de66fceb37da3"/>


android:name="pack_id"

android:value="com.app.test.android" />

android:name=".MusicActivity"

android:label="@string/app_name" >


android:name=".VoiceSdkService"

android:exported="true" >


android:name=

"com.ximalaya.ting.android.opensdk.player.service.XmPlayerService"

/>

2.layout布局文件

layout_musicview.xml

TextView有兩個,tv_name顯示聽書的名稱, tv_totoal_time顯示聽書的總時間。

ProgressBar實時刷新顯示聽書的進度

xmlns:tools="http://schemas.android.com/tools"

android:layout_width="fill_parent"

android:layout_height="wrap_content"

android:background="@android:color/transparent">

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"/>

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"/>

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"/>

activity_music.xml

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" >

android:id="@+id/tv_inputText"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_marginTop="5dp"

android:text="輸入:" />

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="音量:" />

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" />

android:id="@+id/music_view"

android:layout_width="fill_parent"

android:layout_height="80dp"

android:layout_centerInParent="true"

>

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="上海的天氣" />

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="提交" />

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="開始" />

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="停止" />

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="取消" />

自定義MusicView比較簡單,代碼如下:

public class MusicView extendsRelativeLayout{

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, Objectobj);

}

然后把他們分別實現CommunicationAssist接口的變量注冊到OlamiApplication,這樣通過OlamiApplication實現了MusicAcitity和VoiceSdkService橋接。

3.1OlamiApplication

1)注冊MusicActivityVoiceSdkService的回調

public voidsetActivityToServiceListener(CommunicationAssist listener)

{

ActivityToServiceListener = listener;

}

這個是在VoiceSdkService中調用setActivityToServiceListener(),把VoiceSdkService中的VoiceSdkComAssist注冊到application中,MusicActivity中可以通過getActivityToServiceListener

這個函數回調向VoiceSdkService發送消息。

2)注冊VoiceSdkServiceMusicActivity回調

public voidsetServiceToActivityListener(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(newOnClickListener(){

@Override

public void onClick(View v) {

sendMessageToService(MessageConst.CLIENT_ACTION_START_RECORED,0,0,null,null);

}

});

mBtnStop.setOnClickListener(new OnClickListener(){

@Override

public void onClick(View v) {

sendMessageToService(MessageConst.CLIENT_ACTION_STOP_RECORED,0,0,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,0,0,null,null);

}

});

mBtnSend.setOnClickListener(new OnClickListener(){

@Override

public void onClick(View v) {

sendMessageToService(

MessageConst.CLIENT_ACTION_SENT_TEXT,0,0,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 voidhandleMessage(Message msg)

{

switch (msg.what){

caseMessageConst.CLIENT_ACTION_START_RECORED:

break;

default:

break;

}

}

};

}

//InComingHandler收到來自VoiceSdkService的消息用于更新界面,

//包括開始錄音,結束錄音,播放的書的名稱和進度,音量等信息。

private void initInComingHandler()

{

mInComingHandler = new Handler(){

@Override

public void handleMessage(Message msg)

{

switch (msg.what){

caseMessageConst.CLIENT_ACTION_START_RECORED:

mBtnStart.setText("錄音中");

Log.i("led","MusicActivity錄音中");

break;

caseMessageConst.CLIENT_ACTION_STOP_RECORED:

mBtnStart.setText("識別中");

Log.i("led","MusicActivity識別中");

break;

caseMessageConst.CLIENT_ACTION_CANCEL_RECORED:

mBtnStart.setText("開始");

mTextView.setText("已取消");

break;

caseMessageConst.CLIENT_ACTION_ON_ERROR:

mTextView.setText("錯誤代碼:"+msg.arg1);

mBtnStart.setText("開始");

break;

caseMessageConst.CLIENT_ACTION_UPDATA_VOLUME:

mTextViewVolume.setText("音量: "+msg.arg1);

break;

caseMessageConst.SERVER_ACTION_RETURN_RESULT:

//mTextView.setText(msg.obj.toString());

mBtnStart.setText("開始");

break;

caseMessageConst.CLIENT_ACTION_PLAY_BOOK_AFTER_SEARCH:

mBtnStart.setText("開始");

mBookUtil =BookUtil.getInstance();

mBookUtil.play(msg.arg1);

break;

caseMessageConst.CLIENT_ACTION_UPDATA_PLAYING_BOOK_NAME:

mMusicView.setMusicName(msg.obj.toString());

break;

caseMessageConst.CLIENT_ACTION_UPDATE_BOOK_PROGRESS:

int current = msg.arg1;

int duration = msg.arg2;

mMusicView.setProgress(current*100/duration);

float time =duration/1000/60;

mMusicView.setTotalTime("總時間:"+time);

break;

caseMessageConst.CLIENT_ACTION_UPDATA_INPUT_TEXT:

if(msg.obj != null)

mInputTextView.setText("文字:"+msg.obj.toString());

break;

caseMessageConst.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, Bundledata, 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,Objectobj) {

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(2000);//錄音時尾音結束時間,建議填//2000ms

//設置經緯度信息,不愿上傳位置信息,可以填0

mOlamiVoiceRecognizer.setLatitudeAndLongitude(31.155364678184498,121.34882432933009);

}

定義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;

privateBookUtil 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 notifyolami server.

mOlamiVoiceRecognizer.setListener(mOlamiVoiceRecognizerListener);

mOlamiVoiceRecognizer.setLocalization(

OlamiVoiceRecognizer.LANGUAGE_SIMPLIFIED_CHINESE);

mOlamiVoiceRecognizer.setAuthorization(

"51a4bb56ba954655a4fc834bfdc46af1",

"asr","68bff251789b426896e70e888f919a6d","nli");

mOlamiVoiceRecognizer.setVADTailTimeout(2000);

mOlamiVoiceRecognizer.setLatitudeAndLongitude(31.155364678184498,121.34882432933009);

}

private void initHandler()

{

mHandler = new Handler(){

@Override

public void handleMessage(Message msg)

{

switch (msg.what){

caseMessageConst.CLIENT_ACTION_START_RECORED:

sendMessageToActivity(MessageConst.CLIENT_ACTION_START_RECORED,0,0,null,null);

break;

case MessageConst.CLIENT_ACTION_STOP_RECORED:

sendMessageToActivity(MessageConst.CLIENT_ACTION_STOP_RECORED,0,0,null,null);

break;

caseMessageConst.CLIENT_ACTION_ON_ERROR:

sendMessageToActivity(MessageConst.CLIENT_ACTION_ON_ERROR,msg.arg1,0,null,null);

break;

caseMessageConst.CLIENT_ACTION_PLAY_BOOK_AFTER_SEARCH:

sendMessageToActivity(MessageConst.

CLIENT_ACTION_PLAY_BOOK_AFTER_SEARCH,msg.arg1, 0, null, msg.obj);

break;

caseMessageConst.CLIENT_ACTION_UPDATA_PLAYING_BOOK_NAME:

sendMessageToActivity(MessageConst.

CLIENT_ACTION_UPDATA_PLAYING_BOOK_NAME, msg.arg1, 0, null, msg.obj);

break;

caseMessageConst.CLIENT_ACTION_UPDATE_BOOK_PROGRESS:

sendMessageToActivity(MessageConst.

CLIENT_ACTION_UPDATE_BOOK_PROGRESS,msg.arg1, msg.arg2, null, null);

break;

caseMessageConst.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){

caseMessageConst.CLIENT_ACTION_START_RECORED:

if(mOlamiVoiceRecognizer !=null)

mOlamiVoiceRecognizer.start();

break;

caseMessageConst.CLIENT_ACTION_STOP_RECORED:

if(mOlamiVoiceRecognizer !=null)

mOlamiVoiceRecognizer.stop();

break;

caseMessageConst.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 implementsIOlamiVoiceRecognizerListener{

@Override

public void onError(int errCode) {

mHandler.sendMessage(mHandler.obtainMessage(

MessageConst.CLIENT_ACTION_ON_ERROR,errCode,0));

}

@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,0,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,0,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(0);

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, 0, 0, null, input);

serverMessage =jObj.optJSONObject("desc_obj").opt("result").toString();

sendMessageToActivity(MessageConst.

CLIENT_ACTION_UPDATA_SERVER_MESSAGE, 0, 0, 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(0);

input =jObjSemantic.optString("input");

jArraySlots =jObjSemantic.optJSONArray("slots");

jArrayModifier =jObjSemantic.optJSONArray("modifier");

String modifier =(String)jArrayModifier.opt(0);

if((jArrayModifier != null)&& ("play".equals(modifier)))

{

if(jArraySlots != null)

for(inti=0,k=jArraySlots.length(); i

{

JSONObject obj =jArraySlots.getJSONObject(i);

String name =obj.optString("name");

if("singer".equals(name))

singer =obj.optString("value");

elseif("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 = 0;

if(jArraySlots != null)

for(inti=0,k=jArraySlots.length(); i

{

JSONObjectobj = jArraySlots.getJSONObject(i);

JSONObjectjNumDetial = obj.getJSONObject("num_detail");

String index= jNumDetial.optString("recommend_value");

position =Integer.parseInt(index) - 1;

}

if(mBookUtil != null)

mBookUtil.skipTo(position);

}

}

}

if(songName != null)

{

if(singer != null)

{

}else{

mBookUtil.searchBookAndPlay(songName,0,0);

}

}else if(singer != null)

{

mBookUtil.searchBookAndPlay(songName,0,0);

}

serverMessage =jObj.optJSONObject("desc_obj").opt("result").toString();

}

catch (Exception e)

{

e.printStackTrace();

}

//發送消息更新語音識別的文字

sendMessageToActivity(MessageConst.CLIENT_ACTION_UPDATA_INPUT_TEXT, 0,0, null, input);

//發送消息更新服務器返回的結果字符串

sendMessageToActivity(MessageConst.CLIENT_ACTION_UPDATA_SERVER_MESSAGE,

0, 0, null, serverMessage);

}

private void sendMessageToActivity(int what, int arg1, int arg2, Bundledata, 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,Objectobj) {

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

VoiceSdkServiceonResult的回調處理

在VoiceSdkService.java中processServiceMessage(String message)用于處理onResult的回調數據。例如“我要聽三國演義”返回如下數據:

{

"data": {

"asr": {

"result":"我要聽三國演義",

"speech_status":0,

"final":true,

"status":0

},

"nli": [

{

"desc_obj": {

"result":"正在努力搜索中,請稍等",

"status":0

},

"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(StringbookName,final int index,final boolean isNeedPlay)

{

mBookName = bookName;

Map param = new HashMap();

param.put(DTransferConstants.SEARCH_KEY, bookName);

param.put(DTransferConstants.CATEGORY_ID, "" + 3);//此處3代表搜索的是聽書

//param.put(DTransferConstants.PAGE, "" + mPageId);

param.put(DTransferConstants.SORT, "asc");//返回列表的排序是正序還是逆序

param.put(DTransferConstants.PAGE_SIZE, "" + PAGE_SIZE);//每頁能返回多少個查詢結果

mPage = (index/PAGE_SIZE)+1;//當前在第幾頁

mPlayerManager = XmPlayerManager.getInstance(mContext);//喜馬拉雅初始化部分

mPlayerManager.init(mNotificationId, null);

mPlayerManager.addPlayerStatusListener(mPlayerStatusListener);

mPlayerManager.addAdsStatusListener(mAdsListener);

CommonRequest.getSearchedAlbums(param, newIDataCallBack()

{

@Override

public void onSuccess(SearchAlbumList object)

{

if (object != null && object.getAlbums() != null

&&object.getAlbums().size() != 0)

{

if (mSearchAlbumList == null)

{

mSearchAlbumList = object;

}

else

{

mSearchAlbumList.getAlbums().addAll(object.getAlbums());

}

//mTrackAdapter.notifyDataSetChanged();

Map map =new HashMap();

map.put(

DTransferConstants.ALBUM_ID,""+object.getAlbums().get(0).getId());

map.put(DTransferConstants.SORT, "asc");

map.put(DTransferConstants.PAGE, "" + mPage);

map.put(DTransferConstants.PAGE_SIZE,"" + PAGE_SIZE);

CommonRequest.getTracks(map,new IDataCallBack()

{

@Override

public voidonSuccess(TrackList object)

{

mTrackList =object;

mTotalCount =mTrackList.getTotalCount();

if(mTrackList.getTracks().size() <= 0)

return;

String str = "專輯:"+mTrackList.getAlbumTitle()+

get(0).getTrackTitle().toString();

if(isNeedPlay)

{

mPosition =index % PAGE_SIZE;

mHandler.sendMessage(mHandler.obtainMessageMessageConst.CLIENT_ACTION_PLAY_BOOK_AFTER_SEARCH,

index %PAGE_SIZE,0));//此處mTrackList中已經查詢出結果

//向VoiceSdkService發送消息進行播放

}

else

sendBookInfoToServer();

}

@Override

public void onError(intcode, 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.源碼下載鏈接

https://github.com/ls0609/olami_musicdemo

7.相關博客

語音識別語義理解一站式解決(android平臺&olami sdk)

http://blog.csdn.net/ls0609/article/details/71519203

olami開放平臺語法編寫簡介:http://blog.csdn.net/ls0609/article/details/71624340

olami開放平臺語法官方介紹:https://cn.olami.ai/wiki/?mp=nli&content=nli2.html

csdn博文:http://blog.csdn.net/ls0609/article/details/71519203

?

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,748評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,165評論 3 414
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,595評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,633評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,435評論 6 405
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,943評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,035評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,175評論 0 287
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,713評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,599評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,788評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,303評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,034評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,412評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,664評論 1 280
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,408評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,747評論 2 370

推薦閱讀更多精彩內容