20212421 2023-2024-2 《移动平台开发与实践》第6次作业
一、实验目标及内容
掌握基于Android平台的程序设计技术,并能够编写完成语音识别系统。
设计并开发一个语音识别应用系统。
通过使用RecognizerIntent实现语音识别功能,开发一个Android语音识别系统。
二、实验过程
1.实验准备
点击进入科大讯飞控制台,注册登录账户后,创建新应用:
可以参考如下配置:
完成后,红框处是实验所需要用到的:
下载实验所需的文件:
解压缩后,将如图部分复制粘贴到工程libs文件下,assets文件复制到mian文件下:
在build.gradle.kts中的android{}中添加如下代码,并按下图添加jar包:
sourceSets {
getByName("main") {
jniLibs.srcDirs("libs")
}
}
2.语音实验
布局文件输入:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical"
tools:context=".MainActivity">
<Button
android:id="@+id/btn_click"
android:text="点击开始语音识别"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
<EditText
android:id="@+id/result"
android:layout_below="@id/btn_click"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="此处显示你所录下的内容"
/>
</LinearLayout>
在AndroidManifest.xml中添加权限:
<!--连接网络权限,用于执行云端语音能力 -->
<uses-permission android:name="android.permission.INTERNET"/>
<!--获取手机录音机使用权限,听写、识别、语义理解需要用到此权限 -->
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
<uses-permission android:name="Manifest.permission.RECORD_AUDIO" />
<!--读取网络信息状态 -->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<!--获取当前wifi状态 -->
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<!--允许程序改变网络连接状态 -->
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE"/>
<!--读取手机信息权限 -->
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<!--读取联系人权限,上传联系人需要用到此权限 -->
<uses-permission android:name="android.permission.READ_CONTACTS"/>
<!--外存储写权限,构建语法需要用到此权限 -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<!--外存储读权限,构建语法需要用到此权限 -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<!--配置权限,用来记录应用配置信息 -->
<uses-permission android:name="android.permission.WRITE_SETTINGS"
tools:ignore="ProtectedPermissions" />
新建一个kotlin类文件,输入:
package com.example.talktest
import android.content.Context
import android.view.View
import android.widget.TextView
import com.example.talktest.MainActivity.XunFeiCallbackListener
import com.iflytek.cloud.RecognizerResult
import com.iflytek.cloud.SpeechConstant
import com.iflytek.cloud.SpeechError
import com.iflytek.cloud.SpeechUtility
import com.iflytek.cloud.ui.RecognizerDialog
import com.iflytek.cloud.ui.RecognizerDialogListener
import org.json.JSONObject
import org.json.JSONTokener
object XunFeiUtil {
var appid: String = "c4307dd3"//自己申请的appid
fun initXunFei(context: Context?) {
SpeechUtility.createUtility(context, SpeechConstant.APPID + "=" + appid)
}
fun startVoice(context: Context?, callbackListener: XunFeiCallbackListener) {
val dialog = RecognizerDialog(context, null)
dialog.setParameter(SpeechConstant.LANGUAGE, "zh_cn")
dialog.setParameter(SpeechConstant.ACCENT, "mandarin")
dialog.setParameter(SpeechConstant.ASR_PTT, "0")
dialog.setListener(object : RecognizerDialogListener {
override fun onResult(recognizerResult: RecognizerResult, b: Boolean) {
callbackListener.onFinish(recognizerResult)
}
override fun onError(speechError: SpeechError) {
}
})
dialog.show()
//Toast.makeText(this, "请开始说话", Toast.LENGTH_SHORT).show();
//提示语为空,不显示提示语
val txt = dialog.window!!.decorView.findViewWithTag<View>("textlink") as TextView
txt.text = ""
}
fun parseIatResult(json: String?): String {
val ret = StringBuffer()
try {
val tokener = JSONTokener(json)
val joResult = JSONObject(tokener)
val words = joResult.getJSONArray("ws")
for (i in 0 until words.length()) {
// 转写结果词,默认使用第一个结果
val items = words.getJSONObject(i).getJSONArray("cw")
val obj = items.getJSONObject(0)
ret.append(obj.getString("w"))
}
} catch (e: Exception) {
e.printStackTrace()
}
return ret.toString()
}
}
在MainActivity中实现一个接口和麦克风权限的动态获取:
interface XunFeiCallbackListener {
fun onFinish(results: RecognizerResult?)
}
// 定义麦克风权限
private val PERMISSION_MICROPHONE = Manifest.permission.RECORD_AUDIO
// 如果需要同时请求存储和麦克风权限,可以定义一个包含所有权限的数组
private val PERMISSIONS_ALL = arrayOf(
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE,
PERMISSION_MICROPHONE
)
// 请求权限的请求码
private val REQUEST_PERMISSION_CODE = 3
。。。。。。。。。。。。。。。。。。。
// 检查并请求麦克风权限
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (ContextCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO)
!= PackageManager.PERMISSION_GRANTED) {
// 请求麦克风权限
ActivityCompat.requestPermissions(this,
arrayOf(Manifest.permission.RECORD_AUDIO),
REQUEST_PERMISSION_CODE)
}
}
。。。。。。。。。。。。。。。。
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<out String>,
grantResults: IntArray
) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
if (requestCode == REQUEST_PERMISSION_CODE) {
if ((grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED)) {
// 麦克风权限被授予,可以继续进行语音识别等操作
} else {
// 麦克风权限被拒绝,处理这种情况(例如,显示一个提示或禁用某些功能)
}
}
}
完整代码:
package com.example.talktest
import android.Manifest
import android.app.Activity
import android.content.pm.PackageManager
import android.os.Build
import android.os.Bundle
import android.view.View
import android.widget.Button
import android.widget.EditText
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import com.example.talktest.XunFeiUtil.initXunFei
import com.example.talktest.XunFeiUtil.parseIatResult
import com.example.talktest.XunFeiUtil.startVoice
import com.iflytek.cloud.RecognizerResult
class MainActivity : AppCompatActivity(), View.OnClickListener {
private var btn_click: Button? = null
private var mResultText: EditText? = null
// 定义麦克风权限
private val PERMISSION_MICROPHONE = Manifest.permission.RECORD_AUDIO
// 如果需要同时请求存储和麦克风权限,可以定义一个包含所有权限的数组
private val PERMISSIONS_ALL = arrayOf(
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE,
PERMISSION_MICROPHONE
)
// 请求权限的请求码
private val REQUEST_PERMISSION_CODE = 3
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
initXunFei(this)
btn_click = findViewById<View>(R.id.btn_click) as Button
mResultText = (findViewById<View>(R.id.result) as EditText)
btn_click!!.setOnClickListener(this)
// 检查并请求麦克风权限
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (ContextCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO)
!= PackageManager.PERMISSION_GRANTED) {
// 请求麦克风权限
ActivityCompat.requestPermissions(this,
arrayOf(Manifest.permission.RECORD_AUDIO),
REQUEST_PERMISSION_CODE)
}
}
}
interface XunFeiCallbackListener {
fun onFinish(results: RecognizerResult?)
}
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<out String>,
grantResults: IntArray
) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
if (requestCode == REQUEST_PERMISSION_CODE) {
if ((grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED)) {
// 麦克风权限被授予,可以继续进行语音识别等操作
} else {
// 麦克风权限被拒绝,处理这种情况(例如,显示一个提示或禁用某些功能)
}
}
}
override fun onClick(v: View) {
if (ContextCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO)
== PackageManager.PERMISSION_GRANTED){
startVoice(this, object : XunFeiCallbackListener {
override fun onFinish(results: RecognizerResult?) {
val text: String = parseIatResult(results?.resultString)
// 自动填写地址
mResultText!!.append(text)
}
})
}
else{
Toast.makeText(this,"没有权限",Toast.LENGTH_LONG).show()
}
}
}
实验结果:
语音识别
三、实验问题及解决方案
问题1:.so文件重复
解决方案:在运行代码时,代码没有问题,但总是运行失败,后发现jniLibs文件下有重复的.so文件,将重复的部分删掉就行。
问题2:麦克风权限的动态申请
解决方案:详细见实验参考的申请格式,查询相应的麦克风权限名称,转化为kotlin代码即可。
问题3:消除语音识别下的文字
解决方案:详细见实验参考。
四、实验感悟
这次实验让我对语音识别技术有了更深入的了解和认识。这次实验与上一次的百度地图有异曲同工之妙。在实验中,我也遇到过问题,但在网上查找资料后就基本都解决了。其中动态权限的申请之类的还是比较重要的。开始在真机上测试时,就因为没有申请麦克风权限,导致一直不能进行语音识别,只能手动的设置软件的权限管理,最后通过查询资料,也实现了麦克风权限的动态申请,也就不用手动那么麻烦了。
五、实验参考
1:Android studio实现语音转文字功能
2:Android studio 动态获取权限
3:Dialog中语音识别能力由讯飞输入法提供去掉这几个字