轉載請注明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)注冊MusicActivity到VoiceSdkService的回調
public voidsetActivityToServiceListener(CommunicationAssist listener)
{
ActivityToServiceListener = listener;
}
這個是在VoiceSdkService中調用setActivityToServiceListener(),把VoiceSdkService中的VoiceSdkComAssist注冊到application中,MusicActivity中可以通過getActivityToServiceListener
這個函數回調向VoiceSdkService發送消息。
2)注冊VoiceSdkService到MusicActivity回調
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
VoiceSdkService中onResult的回調處理
在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
?