功能需求:
(1)语音识别,将语音识别为文字,用于语音文字输入功能。
(2)语音播报,将文字通过语音的形式播放出来。
主要思路:
(1)语音识别:使用百度的第三方免费语音识别SDK。(特别注意,只要是使用第三方,强烈建议直接看官方文档,不要看一些博文什么玩意的,除非它的日期是非常非常新的。)
(2)语音播报:使用Android自带的TextToSpeech控件即可。
效果图:
【语音识别】功能步骤如下:
一、登录百度AI开放平台:http://ai.baidu.com/,选择【开发资源】下的【SDK下载】,然后下载相应的SDK,如下图
(备注:里面包含完整Demo,特别注意,一定要看【使用说明】)
二、解压下载好的压缩包文件,将SDK集成到项目中,即导入相应的jar包和so库文件,导入后的目录如下:
(备注:1、将jar包添加到libs下,并add as Modules。2、在main下创建jniLibs文件夹,并把相应的so库文件添加进去)
三、修改AndroidManifest.xml清单文件,添加申请到的APP_ID,API_KEY,SECRET_KEY到application中,如下图:
(备注:上述三个信息,自己到控制台里的应用列表中,创建一个新的应用,并且选中百度语音接口,确定之后,就可以在应用列表中找到你想要的信息。)
四、准备工作已完成,接下来就可以直接使用该SDK进行开发了。相应的MainActivity.java代码如下:
public class MainActivity extends AppCompatActivity implements View.OnClickListener, EventListener {
private Context mContext;
private RxPermissions rxPermissions;
private TextView tvResult, tvLog;
private Button btnStop, btnStart;
private LinearLayout lLayoutLoading;
private EventManager eventManager;
protected boolean enableOffline = false; // 测试离线命令词,需要改成true
private String[] arrayResult;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
baseDataInit();
checkUserPermissions();
bindViews();
viewsAddListener();
viewsDataInit();
}
@Override
protected void onDestroy() {
super.onDestroy();
// 基于SDK集成4.2 发送取消事件
eventManager.send(SpeechConstant.ASR_CANCEL, "{}", null, 0, 0);
if (enableOffline) {
unloadOfflineEngine(); // 测试离线命令词请开启, 测试 ASR_OFFLINE_ENGINE_GRAMMER_FILE_PATH 参数时开启
}
// 基于SDK集成5.2 退出事件管理器
// 必须与registerListener成对出现,否则可能造成内存泄露
eventManager.unregisterListener(this);
}
@Override
protected void onPause() {
super.onPause();
eventManager.send(SpeechConstant.ASR_CANCEL, "{}", null, 0, 0);
}
private void baseDataInit() {
mContext = this;
rxPermissions = new RxPermissions(MainActivity.this);
}
private void bindViews() {
tvResult = findViewById(R.id.Main_tvResult);
tvLog = findViewById(R.id.Main_tvLog);
btnStop = findViewById(R.id.Main_btnStop);
btnStart = findViewById(R.id.Main_btnStart);
lLayoutLoading = findViewById(R.id.LoadingLayout);
}
private void viewsAddListener() {
btnStart.setOnClickListener(this);
btnStop.setOnClickListener(this);
// 基于sdk集成1.1 初始化EventManager对象
eventManager = EventManagerFactory.create(this, "asr");
// 基于sdk集成1.3 注册自己的输出事件类
eventManager.registerListener(this); // EventListener 中 onEvent方法
}
private void viewsDataInit() {
tvResult.setText("语音识别");
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.Main_btnStop: {
stop();
break;
}
case R.id.Main_btnStart: {
btnStart.setEnabled(false);
arrayResult = null;
lLayoutLoading.setVisibility(View.VISIBLE);
tvLog.setText("开始识别……");
start();
break;
}
}
}
@Override
public void onEvent(String s, String s1, byte[] bytes, int i, int i1) {
if (s.equals(SpeechConstant.CALLBACK_EVENT_ASR_PARTIAL)) {
RecognitionResult recognitionResult = RecognitionResult.parseJson(s1);
//临时识别结果
arrayResult = recognitionResult.getResultsRecognition();
} else if (s.equals(SpeechConstant.CALLBACK_EVENT_ASR_FINISH)) {
//最终识别结果
String result = "识别结果:无";
if (arrayResult != null) {
if (arrayResult.length > 0) {
result = "识别结果:" + arrayResult[0];
}
}
tvLog.setText(result);
btnStart.setEnabled(true);
lLayoutLoading.setVisibility(View.GONE);
}
}
/**
* 基于SDK集成2.2 发送开始事件
* 点击开始按钮
* 测试参数填在这里
*/
private void start() {
Map params = new LinkedHashMap();
String event = null;
event = SpeechConstant.ASR_START; // 替换成测试的event
if (enableOffline) {
params.put(SpeechConstant.DECODER, 2);
}
// 基于SDK集成2.1 设置识别参数
params.put(SpeechConstant.ACCEPT_AUDIO_VOLUME, false);
// 请先使用如‘在线识别’界面测试和生成识别参数。 params同ActivityRecog类中myRecognizer.start(params);
// 复制此段可以自动检测错误
(new AutoCheck(getApplicationContext(), new Handler() {
public void handleMessage(Message msg) {
if (msg.what == 100) {
AutoCheck autoCheck = (AutoCheck) msg.obj;
synchronized (autoCheck) {
String message = autoCheck.obtainErrorMessage(); // autoCheck.obtainAllMessage();
Log.e("AutoCheckMessage", message);
}
}
}
}, enableOffline)).checkAsr(params);
String json = null; // 可以替换成自己的json
json = new JSONObject(params).toString(); // 这里可以替换成你需要测试的json
eventManager.send(event, json, null, 0, 0);
Log.e("输入参数", json);
}
/**
* 点击停止按钮
* 基于SDK集成4.1 发送停止事件
*/
private void stop() {
Log.e("停止识别", "ASR_STOP");
eventManager.send(SpeechConstant.ASR_STOP, null, null, 0, 0);
}
/**
* enableOffline为true时,在onDestory中调用,与loadOfflineEngine对应
* 基于SDK集成5.1 卸载离线资源步骤(离线时使用)
*/
private void unloadOfflineEngine() {
eventManager.send(SpeechConstant.ASR_KWS_UNLOAD_ENGINE, null, null, 0, 0); //
}
/**
* 检查并获取用户权限
*/
private void checkUserPermissions() {
rxPermissions
.requestEach(Manifest.permission.RECORD_AUDIO,
Manifest.permission.ACCESS_NETWORK_STATE,
Manifest.permission.INTERNET,
Manifest.permission.READ_PHONE_STATE,
Manifest.permission.WRITE_EXTERNAL_STORAGE
)
.subscribe(permission -> {
if (permission.granted) {
} else if (permission.shouldShowRequestPermissionRationale) {
} else {}
});
}
}
至此,语音识别功能已完成。
【语音播报】功能步骤如下:
这个是用了TextToSpeech控件,很简单,主要是两个步骤:
(1)创建一个TextToSpeech实例,并实现相应的OnInitListener接口。
(2)然后通过speak()方法来开始播报,通过stop()方法来停止播报。
直接上代码了,ContentActivity.java的代码如下:
public class ContentActivity extends AppCompatActivity implements View.OnClickListener, OnInitListener {
private static final int LOADING_GONE = 1001;
private static final int LOADING_VISIBLE = 1002;
private Context mContext;
private EditText etContent;
private Button[] arrayBtnFunc;
private TextToSpeech textToSpeech;
private LinearLayout lLayoutLoading;
private ScheduledExecutorService scheduledExecutorService;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_content);
baseDataInit();
bindViews();
viewsAddListener();
autoCheckSpeakState();
}
@Override
protected void onDestroy() {
if (textToSpeech != null) {
textToSpeech.stop();
textToSpeech.shutdown();
}
scheduledExecutorService.shutdown();
super.onDestroy();
}
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case LOADING_GONE: {
lLayoutLoading.setVisibility(View.GONE);
break;
}
case LOADING_VISIBLE: {
lLayoutLoading.setVisibility(View.VISIBLE);
break;
}
default:break;
}
}
};
private void baseDataInit() {
mContext = this;
scheduledExecutorService = Executors.newScheduledThreadPool(1);
}
private void bindViews() {
etContent = findViewById(R.id.Content_etContent);
arrayBtnFunc = new Button[] {
findViewById(R.id.Content_btnStart),
findViewById(R.id.Content_btnStop)
};
lLayoutLoading = findViewById(R.id.LoadingLayout);
textToSpeech = new TextToSpeech(mContext, this::onInit);
}
private void viewsAddListener() {
for (int i = 0; i < arrayBtnFunc.length; i ++) {
arrayBtnFunc[i].setOnClickListener(this::onClick);
}
}
/**
* 检测是否播报完成(定时)
*/
private void autoCheckSpeakState() {
scheduledExecutorService.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
if (textToSpeech != null && textToSpeech.isSpeaking()) {
mHandler.sendEmptyMessage(LOADING_VISIBLE);
} else {
mHandler.sendEmptyMessage(LOADING_GONE);
}
}
}, 1, 200, TimeUnit.MILLISECONDS);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.Content_btnStart: {
lLayoutLoading.setVisibility(View.VISIBLE);
String content = etContent.getText().toString().trim();
if (!content.equals("")) {
textToSpeech.speak(etContent.getText().toString(), TextToSpeech.QUEUE_FLUSH, null);
} else {
Toast.makeText(mContext, "请输入内容!", Toast.LENGTH_SHORT).show();
}
break;
}
case R.id.Content_btnStop: {
textToSpeech.stop();
break;
}
default:break;
}
}
@Override
public void onInit(int status) {
if (status == TextToSpeech.SUCCESS) {
//默认设定语言为中文,原生的android貌似不支持中文。
int result = textToSpeech.setLanguage(Locale.CHINESE);
if (result == TextToSpeech.LANG_MISSING_DATA || result == TextToSpeech.LANG_NOT_SUPPORTED){
Toast.makeText(mContext, "目前不支持中文!", Toast.LENGTH_SHORT).show();
}else{
//不支持中文就将语言设置为英文
textToSpeech.setLanguage(Locale.US);
}
}
}
特别注意:一定要注意权限问题!!!
相应的Demo地址为:https://download.csdn.net/download/lpcrazyboy/11195714