语音识别,语义理解一站式解决(android平台olami sdk)
語音記賬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>- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
2.layout布局文件
layout_musicview.xml
TextView 有兩個,tv_name顯示聽書的名稱, tv_totoal_time顯示聽書的總時間。?
ProgressBar 實時刷新顯示聽書的進度
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
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" ><TextViewandroid:id="@+id/tv_inputText"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginTop="5dp"android:text="輸入:" /><TextViewandroid: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="音量:" /><TextViewandroid: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.MusicViewandroid:id="@+id/music_view"android:layout_width="fill_parent"android:layout_height="80dp"android:layout_centerInParent="true"></com.olami.musicdemo.MusicView><EditTextandroid: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="上海的天氣" /> <Buttonandroid: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="提交" /><Buttonandroid:id="@+id/btn_start"android:layout_width="wrap_content"android:layout_height="wrap_content" android:layout_alignParentBottom="true"android:layout_centerHorizontal="true"android:text="開始" /><Buttonandroid: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="停止" /><Buttonandroid: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>- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
自定義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);}}- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
布局效果圖如下:?
3.MusicActivity和VoiceSdkService通信
本文沒有用bind service的方式實現activity和service的消息通信。?
MusicAcitity 和 VoiceSdkService中分別實現了一個CommunicationAssist的接口
- 1
- 2
- 3
- 1
- 2
- 3
然后把他們分別實現CommunicationAssist接口的變量注冊到OlamiApplication,這樣通過OlamiApplication實現了MusicAcitity 和 VoiceSdkService橋接。
3.1OlamiApplication
1) 注冊MusicActivity到VoiceSdkService的回調
public void setActivityToServiceListener(CommunicationAssist listener) {ActivityToServiceListener = listener; }- 1
- 2
- 3
- 4
- 1
- 2
- 3
- 4
這個是在VoiceSdkService中調用setActivityToServiceListener(),把VoiceSdkService中的VoiceSdkComAssist注冊到application中,MusicActivity中可以通過getActivityToServiceListener?
這個函數回調向VoiceSdkService發送消息。
2) 注冊 VoiceSdkService到MusicActivity回調
public void setServiceToActivityListener(CommunicationAssist listener) {mServiceToActivityListener = listener; }- 1
- 2
- 3
- 4
- 1
- 2
- 3
- 4
這個是在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;@Overrideprotected 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(){@Overridepublic void onClick(View v) {sendMessageToService(MessageConst.CLIENT_ACTION_START_RECORED,0,0,null,null);} });mBtnStop.setOnClickListener(new OnClickListener(){@Overridepublic 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(){@Overridepublic void onClick(View v) {sendMessageToService(MessageConst.CLIENT_ACTION_CANCEL_RECORED,0,0,null,null);} });mBtnSend.setOnClickListener(new OnClickListener(){@Overridepublic 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(){@Overridepublic void handleMessage(Message msg){switch (msg.what){case MessageConst.CLIENT_ACTION_START_RECORED:break;default:break; }}};}//InComingHandler 收到來自VoiceSdkService的消息用于更新界面,//包括開始錄音,結束錄音,播放的書的名稱和進度,音量等信息。private void initInComingHandler(){mInComingHandler = new Handler(){@Overridepublic 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*100/duration);float time = duration/1000/60;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發送過來的消息@Overridepublic 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);} }@Overridepublic void onDestroy() {//退出應用,停止VoiceSdkService,會進行資源的釋放super.onDestroy();Intent intent = new Intent();intent.setClass(MusicActivity.this, VoiceSdkService.class);stopService(intent);} }- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145
- 146
- 147
- 148
- 149
- 150
- 151
- 152
- 153
- 154
- 155
- 156
- 157
- 158
- 159
- 160
- 161
- 162
- 163
- 164
- 165
- 166
- 167
- 168
- 169
- 170
- 171
- 172
- 173
- 174
- 175
- 176
- 177
- 178
- 179
- 180
- 181
- 182
- 183
- 184
- 185
- 186
- 187
- 188
- 189
- 190
- 191
- 192
- 193
- 194
- 195
- 196
- 197
- 198
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145
- 146
- 147
- 148
- 149
- 150
- 151
- 152
- 153
- 154
- 155
- 156
- 157
- 158
- 159
- 160
- 161
- 162
- 163
- 164
- 165
- 166
- 167
- 168
- 169
- 170
- 171
- 172
- 173
- 174
- 175
- 176
- 177
- 178
- 179
- 180
- 181
- 182
- 183
- 184
- 185
- 186
- 187
- 188
- 189
- 190
- 191
- 192
- 193
- 194
- 195
- 196
- 197
- 198
3.3 VoiceSdkService
@Override public void onCreate() {initHandler();//用于內部消息處理initInComingHandler();//用于處理來自MusicActivity的消息initCommunicationAssist();//向application注冊消息回調,這樣MusicActivity可//以通過getActivityToServiceListener()回調向VoiceSdkService發送消息initViaVoiceRecognizerListener();//初始化錄音識別回調listenerinit();//olami錄音識別引擎初始化initXmly();//喜馬拉雅初始化}- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
定義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;@Overridepublic void onCreate() {initHandler();initInComingHandler();initCommunicationAssist();initViaVoiceRecognizerListener();init();initXmly();}@Overridepublic IBinder onBind(Intent intent) {// TODO Auto-generated method stubreturn 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(2000);mOlamiVoiceRecognizer.setLatitudeAndLongitude(31.155364678184498,121.34882432933009); }private void initHandler(){mHandler = new Handler(){@Overridepublic void handleMessage(Message msg){switch (msg.what){case MessageConst.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;case MessageConst.CLIENT_ACTION_ON_ERROR:sendMessageToActivity(MessageConst.CLIENT_ACTION_ON_ERROR,msg.arg1,0,null,null);break;case MessageConst.CLIENT_ACTION_PLAY_BOOK_AFTER_SEARCH:sendMessageToActivity(MessageConst.CLIENT_ACTION_PLAY_BOOK_AFTER_SEARCH, msg.arg1, 0, null, msg.obj);break;case MessageConst.CLIENT_ACTION_UPDATA_PLAYING_BOOK_NAME:sendMessageToActivity(MessageConst.CLIENT_ACTION_UPDATA_PLAYING_BOOK_NAME, msg.arg1, 0, 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(){@Overridepublic 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{@Overridepublic void onError(int errCode) {mHandler.sendMessage(mHandler.obtainMessage(MessageConst.CLIENT_ACTION_ON_ERROR,errCode,0));}@Overridepublic void onEndOfSpeech() {mHandler.sendEmptyMessage(MessageConst.CLIENT_ACTION_STOP_RECORED);if(mIsRecordPause){mIsRecordPause = false;mBookUtil.resumePlay();}}@Overridepublic void onBeginningOfSpeech() {if(mBookUtil.isPlaying()){mBookUtil.pause();mIsRecordPause = true;}mHandler.sendEmptyMessage(MessageConst.CLIENT_ACTION_START_RECORED);}@Overridepublic void onResult(String result, int type) { sendMessageToActivity(MessageConst.SERVER_ACTION_RETURN_RESULT,type,0,null,result);processServiceMessage(result);}@Overridepublic void onCancel() {mHandler.sendEmptyMessage(MessageConst.CLIENT_ACTION_CANCEL_RECORED);}@Overridepublic 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(int i=0,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 = 0;if(jArraySlots != null)for(int i=0,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) - 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, Bundle data, Object obj){if(OlamiApplication.getInstance().getServiceToActivityListener() != null)OlamiApplication.getInstance().getServiceToActivityListener().callBack(what, arg1, arg2, data, obj);}private class VoiceSdkComAssist implements CommunicationAssist{@Overridepublic 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);} }@Overridepublic void onDestroy(){super.onDestroy();if(mOlamiVoiceRecognizer != null)mOlamiVoiceRecognizer.destroy();if(mBookUtil != null){mBookUtil.destroy();}}}- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145
- 146
- 147
- 148
- 149
- 150
- 151
- 152
- 153
- 154
- 155
- 156
- 157
- 158
- 159
- 160
- 161
- 162
- 163
- 164
- 165
- 166
- 167
- 168
- 169
- 170
- 171
- 172
- 173
- 174
- 175
- 176
- 177
- 178
- 179
- 180
- 181
- 182
- 183
- 184
- 185
- 186
- 187
- 188
- 189
- 190
- 191
- 192
- 193
- 194
- 195
- 196
- 197
- 198
- 199
- 200
- 201
- 202
- 203
- 204
- 205
- 206
- 207
- 208
- 209
- 210
- 211
- 212
- 213
- 214
- 215
- 216
- 217
- 218
- 219
- 220
- 221
- 222
- 223
- 224
- 225
- 226
- 227
- 228
- 229
- 230
- 231
- 232
- 233
- 234
- 235
- 236
- 237
- 238
- 239
- 240
- 241
- 242
- 243
- 244
- 245
- 246
- 247
- 248
- 249
- 250
- 251
- 252
- 253
- 254
- 255
- 256
- 257
- 258
- 259
- 260
- 261
- 262
- 263
- 264
- 265
- 266
- 267
- 268
- 269
- 270
- 271
- 272
- 273
- 274
- 275
- 276
- 277
- 278
- 279
- 280
- 281
- 282
- 283
- 284
- 285
- 286
- 287
- 288
- 289
- 290
- 291
- 292
- 293
- 294
- 295
- 296
- 297
- 298
- 299
- 300
- 301
- 302
- 303
- 304
- 305
- 306
- 307
- 308
- 309
- 310
- 311
- 312
- 313
- 314
- 315
- 316
- 317
- 318
- 319
- 320
- 321
- 322
- 323
- 324
- 325
- 326
- 327
- 328
- 329
- 330
- 331
- 332
- 333
- 334
- 335
- 336
- 337
- 338
- 339
- 340
- 341
- 342
- 343
- 344
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145
- 146
- 147
- 148
- 149
- 150
- 151
- 152
- 153
- 154
- 155
- 156
- 157
- 158
- 159
- 160
- 161
- 162
- 163
- 164
- 165
- 166
- 167
- 168
- 169
- 170
- 171
- 172
- 173
- 174
- 175
- 176
- 177
- 178
- 179
- 180
- 181
- 182
- 183
- 184
- 185
- 186
- 187
- 188
- 189
- 190
- 191
- 192
- 193
- 194
- 195
- 196
- 197
- 198
- 199
- 200
- 201
- 202
- 203
- 204
- 205
- 206
- 207
- 208
- 209
- 210
- 211
- 212
- 213
- 214
- 215
- 216
- 217
- 218
- 219
- 220
- 221
- 222
- 223
- 224
- 225
- 226
- 227
- 228
- 229
- 230
- 231
- 232
- 233
- 234
- 235
- 236
- 237
- 238
- 239
- 240
- 241
- 242
- 243
- 244
- 245
- 246
- 247
- 248
- 249
- 250
- 251
- 252
- 253
- 254
- 255
- 256
- 257
- 258
- 259
- 260
- 261
- 262
- 263
- 264
- 265
- 266
- 267
- 268
- 269
- 270
- 271
- 272
- 273
- 274
- 275
- 276
- 277
- 278
- 279
- 280
- 281
- 282
- 283
- 284
- 285
- 286
- 287
- 288
- 289
- 290
- 291
- 292
- 293
- 294
- 295
- 296
- 297
- 298
- 299
- 300
- 301
- 302
- 303
- 304
- 305
- 306
- 307
- 308
- 309
- 310
- 311
- 312
- 313
- 314
- 315
- 316
- 317
- 318
- 319
- 320
- 321
- 322
- 323
- 324
- 325
- 326
- 327
- 328
- 329
- 330
- 331
- 332
- 333
- 334
- 335
- 336
- 337
- 338
- 339
- 340
- 341
- 342
- 343
- 344
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
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
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);//此處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, new IDataCallBack<SearchAlbumList>(){@Overridepublic 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<String, String> map = new HashMap<String, String>();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<TrackList>(){@Overridepublic void onSuccess(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.obtainMessage(MessageConst.CLIENT_ACTION_PLAY_BOOK_AFTER_SEARCH, index % PAGE_SIZE,0));//此處mTrackList中已經查詢出結果//向VoiceSdkService發送消息進行播放}elsesendBookInfoToServer(); }@Overridepublic void onError(int code, String message){Log.i("ppp","error: "+message);sendBookInfoToServer();}});}}@Overridepublic void onError(int code, String message){Log.i("ppp","error: "+message);sendBookInfoToServer();}}); }- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
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
轉載請注明CSDN博文地址:http://blog.csdn.net/ls0609/article/details/71519203
總結
以上是生活随笔為你收集整理的语音识别,语义理解一站式解决(android平台olami sdk)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 用Kotlin开发android平台语音
- 下一篇: Hinton's Dark Knowle