前面就不废话了,像申请应用,获取SDK等等,我相信大家应该都会的,科大讯飞采用的是两种语音听写功能,一种带有UI,一种没有UI,本人还是比较笨的,所以就写了较为简单的不带UI的语音听写,哈哈哈

话不多说,我们开始操作!

第一步:先把下载下来的SDK文件中libs包下文件复制粘贴到app下的libs下,如下图所示:

android 讯飞 语音控制 android讯飞语音播报_android


Msc.jar一定要导入工程中(右击这个jar包,选择Add AS Libraries),然后最重要的一步就是在app的build.gradle文件中的android里面添加

sourceSets {
        main {
            jniLibs.srcDirs = ['libs']
        }
    }

为了让大家能更好的理解我附上截图

android 讯飞 语音控制 android讯飞语音播报_android 讯飞 语音控制_02


记住:是在app的build.gradle文件中!!!第二步:在main文件夹下创建assets文件夹,然后把SDK中的assets文件夹下的文件复制到该目录下,为了大家能听懂我的话,我截图给你们瞅瞅

android 讯飞 语音控制 android讯飞语音播报_json_03


哇,是不是一眼就看懂了啊,哈哈哈哈,果然百闻不如一见!

对了对了,大家千万不要忘记加权限:

<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.CHANGE_NETWORK_STATE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

第三步:创建MyApplication用来注册,话不多说,上代码!

public class SpeechApp extends Application {

@Override
public void onCreate() {
    SpeechUtility.createUtility(SpeechApp.this, "appid=5d269d73");
    super.onCreate();
}
}

大家一定要注意的是appid一定要写自己申请的应用的appid,还有SpeechApp一定要写在清单文件中!

第四步:不知道要注意和说啥了,直接上代码

package com.wjs.iatmethod;
import android.Manifest;
import android.app.Activity;
import android.content.SharedPreferences;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.view.View;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;

import com.iflytek.cloud.ErrorCode;
import com.iflytek.cloud.InitListener;
import com.iflytek.cloud.RecognizerListener;
import com.iflytek.cloud.RecognizerResult;
import com.iflytek.cloud.SpeechConstant;
import com.iflytek.cloud.SpeechError;
import com.iflytek.cloud.SpeechRecognizer;

import org.json.JSONException;
import org.json.JSONObject;

import java.io.File;
import java.util.HashMap;
import java.util.LinkedHashMap;
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
    //录音权限
    private String[] permissions = {Manifest.permission.RECORD_AUDIO};
    private static String TAG = MainActivity.class.getSimpleName();
    // 语音听写对象
    private SpeechRecognizer mIat;
    private Toast mToast;
    private StringBuffer buffer = new StringBuffer();
    private EditText mResultText;
    // 用HashMap存储听写结果
    private HashMap<String, String> mIatResult = new LinkedHashMap<String, String>();
    // 引擎类型
    private String mEngineType = SpeechConstant.TYPE_CLOUD;
    private String resultType = "json";

/**
 * @param savedInstanceState
 */
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    //初始化界面
    initLayout();
    // 初始化识别无UI识别对象
    // 使用SpeechRecognizer对象,可根据回调消息自定义界面;
    mIat = SpeechRecognizer.createRecognizer(MainActivity.this, mInitListener);
    mToast = Toast.makeText(this, "", Toast.LENGTH_SHORT);
    mResultText = (EditText) findViewById(R.id.iat_text);
}

/**
 * 初始化界面
 */
private void initLayout() {
    findViewById(R.id.iat_recognize).setOnClickListener(this);
    findViewById(R.id.iat_stop).setOnClickListener(this);
    findViewById(R.id.iat_cancel).setOnClickListener(this);
}

int ret = 0;//函数调用返回值

/**
 * 点击事件
 *
 * @param view
 */
@Override
public void onClick(View view) {
    if (null == mIat) {
        // 创建单例失败,与 21001 错误为同样原因,参考 http://bbs.xfyun.cn/forum.php?mod=viewthread&tid=9688
        this.showTip("创建对象失败,请确认 libmsc.so 放置正确,且有调用 createUtility 进行初始化");
        return;
    }
    switch (view.getId()) {
        // 开始听写
        // 如何判断一次听写结束:OnResult isLast=true 或者 onError
        case R.id.iat_recognize:
            buffer.setLength(0);
            mResultText.setText(null);
            mIatResult.clear();
            //设置参数
            setParam();
            // 不显示听写对话框
            ret = mIat.startListening(mRecognizeListener);
            if (ret != ErrorCode.SUCCESS) {
                showTip("听写失败,错误码:" + ret + ",请点击网址https://www.xfyun.cn/document/error-code查询解决方案");
            } else {
                showTip("请开始说话…");
            }
            break;
        case R.id.iat_stop: {
            mIat.stopListening();
            showTip("停止听写");
        }
        break;
        case R.id.iat_cancel: {
            mIat.cancel();
            showTip("取消听写");
        }
        break;

        default:
            break;
    }
}

/**
 * 听写监听器
 */
private RecognizerListener mRecognizeListener = new RecognizerListener() {
    @Override
    public void onVolumeChanged(int volume, byte[] date) {
        showTip("当前正在说话,音量大小:" + volume);
    }

    @Override
    public void onBeginOfSpeech() {

    }

    @Override
    public void onEndOfSpeech() {
        // 此回调表示:检测到了语音的尾端点,已经进入识别过程,不再接受语音输入
        showTip("结束说话");
    }

    @Override
    public void onResult(RecognizerResult results, boolean b) {

        Log.d(TAG, results.getResultString());
        if (resultType.equals("json")) {
            printResult(results);

        } else if (resultType.equals("plain")) {
            buffer.append(results.getResultString());
            mResultText.setText(buffer.toString());
            mResultText.setSelection(mResultText.length());
        }

    }

    @Override
    public void onError(SpeechError speechError) {

    }

    @Override
    public void onEvent(int i, int i1, int i2, Bundle bundle) {

    }
};

/**
 * @param results
 */
private void printResult(RecognizerResult results) {
    String text = JsonParser.parseIatResult(results.getResultString());
    String sn = null;
    // 读取json结果中的sn字段
    try {
        JSONObject resultJson = new JSONObject(results.getResultString());
        sn = resultJson.optString("sn");
    } catch (JSONException e) {
        e.printStackTrace();
    }
    mIatResult.put(sn, text);
    StringBuffer resultBuffer = new StringBuffer();
    for (String key : mIatResult.keySet()) {
        resultBuffer.append(mIatResult.get(key));
    }
    mResultText.setText(resultBuffer.toString());
    mResultText.setSelection(mResultText.length());
}

/**
 * 设置参数
 */
private void setParam() {
    // 清空参数
    mIat.setParameter(SpeechConstant.PARAMS, null);

    // 设置听写引擎。TYPE_LOCAL表示本地,TYPE_CLOUD表示云端,TYPE_MIX 表示混合
    mIat.setParameter(SpeechConstant.ENGINE_TYPE, mEngineType);
    // 设置返回结果格式
    mIat.setParameter(SpeechConstant.RESULT_TYPE, resultType);
    // 设置语音前端点:静音超时时间,即用户多长时间不说话则当做超时处理
    mIat.setParameter(SpeechConstant.VAD_BOS, "4000");
    // 设置语音后端点:后端点静音检测时间,即用户停止说话多长时间内即认为不再输入, 自动停止录音
    mIat.setParameter(SpeechConstant.VAD_EOS, "2000");
    // 设置标点符号,设置为"0"返回结果无标点,设置为"1"返回结果有标点
    mIat.setParameter(SpeechConstant.ASR_PTT, "1");
    // 设置音频保存路径,保存音频格式支持pcm、wav,设置路径为sd卡请注意WRITE_EXTERNAL_STORAGE权限
    // 注:AUDIO_FORMAT参数语记需要更新版本才能生效
    mIat.setParameter(SpeechConstant.AUDIO_FORMAT, "wav");
    mIat.setParameter(SpeechConstant.ASR_AUDIO_PATH, getExternalCacheDirs() + File.separator + System.currentTimeMillis() + ".wav");
}

/**
 * 初始化监听器
 */
private InitListener mInitListener = new InitListener() {
    @Override
    public void onInit(int code) {
        Log.e(TAG, "SpeechRecognizer init() code = " + code);
        if (code != ErrorCode.SUCCESS) {
            showTip("初始化失败,错误码:" + code);
        }
    }
};

/**
 * 显示Toast消息
 *
 * @param str
 */
private void showTip(final String str) {
    mToast.setText(str);
    mToast.show();
}
}

特别要注意的是:

mSharedPreferences = getSharedPreferences("wjs.xml", Activity.MODE_PRIVATE);

这里"wjs.xml"是我自己创建用来存放数据的,存放什么数据,其实我也不知道,但是没有办法啊,我当时就是没有这个就是出不来,我能怎么办。。。唉,给大家看看我文件的位置吧。

android 讯飞 语音控制 android讯飞语音播报_android_04


一眼就看出来了吧,哈哈哈!

对了对了,还有json解析的类,这个我是直接复制Demo里面的,安全起见,我还是附上代码吧,哈哈哈哈哈!

/**
* Json结果解析类
*/
public class JsonParser {

public static String parseIatResult(String json) {
	StringBuffer ret = new StringBuffer();
	try {
		JSONTokener tokener = new JSONTokener(json);
		JSONObject joResult = new JSONObject(tokener);

		JSONArray words = joResult.getJSONArray("ws");
		for (int i = 0; i < words.length(); i++) {
			// 转写结果词,默认使用第一个结果
			JSONArray items = words.getJSONObject(i).getJSONArray("cw");
			JSONObject obj = items.getJSONObject(0);
			ret.append(obj.getString("w"));
//				如果需要多候选结果,解析数组其他字段
//				for(int j = 0; j < items.length(); j++)
//				{
//					JSONObject obj = items.getJSONObject(j);
//					ret.append(obj.getString("w"));
//				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		} 
		return ret.toString();
	}

public static String parseGrammarResult(String json) {
	StringBuffer ret = new StringBuffer();
	try {
		JSONTokener tokener = new JSONTokener(json);
		JSONObject joResult = new JSONObject(tokener);

		JSONArray words = joResult.getJSONArray("ws");
		for (int i = 0; i < words.length(); i++) {
			JSONArray items = words.getJSONObject(i).getJSONArray("cw");
			for(int j = 0; j < items.length(); j++)
			{
				JSONObject obj = items.getJSONObject(j);
				if(obj.getString("w").contains("nomatch"))
				{
					ret.append("没有匹配结果.");
					return ret.toString();
				}
				ret.append("【结果】" + obj.getString("w"));
				ret.append("【置信度】" + obj.getInt("sc"));
				ret.append("\n");
			}
		}
	} catch (Exception e) {
		e.printStackTrace();
		ret.append("没有匹配结果.");
	} 
	return ret.toString();
}

public static String parseLocalGrammarResult(String json) {
	StringBuffer ret = new StringBuffer();
	try {
		JSONTokener tokener = new JSONTokener(json);
		JSONObject joResult = new JSONObject(tokener);

		JSONArray words = joResult.getJSONArray("ws");
		for (int i = 0; i < words.length(); i++) {
			JSONArray items = words.getJSONObject(i).getJSONArray("cw");
			for(int j = 0; j < items.length(); j++)
			{
				JSONObject obj = items.getJSONObject(j);
				if(obj.getString("w").contains("nomatch"))
				{
					ret.append("没有匹配结果.");
					return ret.toString();
				}
				ret.append("【结果】" + obj.getString("w"));
				ret.append("\n");
			}
		}
		ret.append("【置信度】" + joResult.optInt("sc"));

	} catch (Exception e) {
		e.printStackTrace();
		ret.append("没有匹配结果.");
	} 
	return ret.toString();
}

public static String parseTransResult(String json, String key) {
	StringBuffer ret = new StringBuffer();
	try {
		JSONTokener tokener = new JSONTokener(json);
		JSONObject joResult = new JSONObject(tokener);
		String errorCode = joResult.optString("ret");
		if(!errorCode.equals("0")) {
			return joResult.optString("errmsg");
		}
		JSONObject transResult = joResult.optJSONObject("trans_result");
		ret.append(transResult.optString(key));
		/*JSONArray words = joResult.getJSONArray("results");
		for (int i = 0; i < words.length(); i++) {
			JSONObject obj = words.getJSONObject(i);
			ret.append(obj.getString(key));
		}*/
	} catch (Exception e) {
		e.printStackTrace();
	}
	return ret.toString();
}
}

大致情况就是这样了,如果,我说如果,大家应该能够弄出来了,哈哈哈哈,主要还是给自己看的,怕自己忘记,当然我也希望对大家有帮助!