Android讯飞语音集成【语音评测3】

前言:

语音评测(SpeechEvaluator):
通过智能语音技术自动对发音水平进行评价、发音错误、缺陷进行定位和问题分析。目前评音评测提供汉语、英语两种语言的评测,支持单字(汉语专有)、词语 和句子朗读三种题型。

效果图:
在这里插入图片描述
1、IseActivity.java

public class IseActivity extends AppCompatActivity implements View.OnClickListener {

    private static final String TAG = "IseActivity";
    private EditText mEvaTextEditText;
    private EditText mResultEditText;
    private Button mIseStartButton;
    private Button iseLanguages, iseTopic, iseResultLevel;
    private EditText iseStartTime, iseEndTime, iseTime;
    private String mLastResult;
    private SpeechEvaluator mIse;
    //切换(汉语、句子、等级)
    private String languageType = "zh_cn", topicType = "read_sentence", resultLevelType = "complete";

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_ise);
        mIse = SpeechEvaluator.createEvaluator(this, null);
        initUI();
        setEvaText();
    }

    private void initUI() {
        mEvaTextEditText = this.findViewById(R.id.ise_eva_text);
        mResultEditText = this.findViewById(R.id.ise_result_text);
        mIseStartButton = this.findViewById(R.id.ise_start);
        iseLanguages = this.findViewById(R.id.ise_languages);
        iseTopic = this.findViewById(R.id.ise_topic);
        iseResultLevel = this.findViewById(R.id.ise_result_level);
        iseStartTime = this.findViewById(R.id.ise_start_time);
        iseEndTime = this.findViewById(R.id.ise_end_time);
        iseTime = this.findViewById(R.id.ise_time);

        mIseStartButton.setOnClickListener(this);
        iseLanguages.setOnClickListener(this);
        iseTopic.setOnClickListener(this);
        iseResultLevel.setOnClickListener(this);
        findViewById(R.id.ise_parse).setOnClickListener(this);
        findViewById(R.id.ise_stop).setOnClickListener(this);
        findViewById(R.id.ise_cancel).setOnClickListener(this);
    }

    @Override
    public void onClick(View view) {
        if (null == mIse) {
            // 创建单例失败,与 21001 错误为同样原因,参考 http://bbs.xfyun.cn/forum.php?mod=viewthread&tid=9688
            showToast("创建对象失败,请确认 libmsc.so 放置正确,且有调用 createUtility 进行初始化");
            return;
        }
        switch (view.getId()) {
            case R.id.ise_start:
                if (mIse == null) {
                    return;
                }
                String evaText = mEvaTextEditText.getText().toString();
                mLastResult = null;
                mResultEditText.setText("");
                mResultEditText.setHint("请朗读以上内容");
                mIseStartButton.setEnabled(false);
                setParams();
                int ret = mIse.startEvaluating(evaText, null, mEvaluatorListener);
                //以下方法为通过直接写入音频的方式进行评测业务
				/*if (ret != ErrorCode.SUCCESS) {
					showTip("识别失败,错误码:" + ret);
				} else {
					showTip(getString(R.string.text_begin_ise));
					byte[] audioData = FucUtil.readAudioFile(IseDemo.this,"isetest.wav");
					if(audioData != null) {
						//防止写入音频过早导致失败
						try{
							new Thread().sleep(100);
						}catch (InterruptedException e) {
							Log.d(TAG,"InterruptedException :"+e);
						}
						mIse.writeAudio(audioData,0,audioData.length);
						mIse.stopEvaluating();
					}
				}*/
                break;
            case R.id.ise_parse:
                // 解析最终结果
                if (!TextUtils.isEmpty(mLastResult)) {
                    XmlResultParser resultParser = new XmlResultParser();
                    Result result = resultParser.parse(mLastResult);
                    if (null != result) {
                        mResultEditText.setText(result.toString());
                    } else {
                        showToast("解析结果为空");
                    }
                }
                break;
            case R.id.ise_stop:
                if (mIse.isEvaluating()) {
                    mResultEditText.setHint("评测已停止,等待结果中...");
                    mIse.stopEvaluating();
                }
                break;
            case R.id.ise_cancel:
                mIse.cancel();
                mIseStartButton.setEnabled(true);
                mResultEditText.setText("");
                mResultEditText.setHint("请点击“开始评测”按钮");
                mLastResult = null;
                break;
            case R.id.ise_languages:
                if (languageType.equals("zh_cn")) {
                    languageType = "en_us";
                    iseLanguages.setText("语种:英语");
                } else {
                    languageType = "zh_cn";
                    iseLanguages.setText("语种:汉语");
                }
                setEvaText();
                break;
            case R.id.ise_topic:
                if (topicType.equals("read_sentence")) {
                    topicType = "read_word";
                    iseTopic.setText("题型:词语");
                } else if (topicType.equals("read_word")) {
                    topicType = "read_syllable";
                    iseTopic.setText("题型:单词");
                } else {
                    topicType = "read_sentence";
                    iseTopic.setText("题型:句子");
                }
                setEvaText();
                break;
            case R.id.ise_result_level:
                if (resultLevelType.equals("complete")) {
                    resultLevelType = "plain";
                    iseResultLevel.setText("等级:plain");
                } else {
                    resultLevelType = "complete";
                    iseResultLevel.setText("等级:complete");
                }
                setEvaText();
                break;
            default:
        }
    }

    // 设置评测试题
    private void setEvaText() {
        String text = "";
        if ("en_us".equals(languageType)) {
            if ("read_word".equals(topicType)) {
                text = getString(R.string.text_en_word);
            } else if ("read_sentence".equals(topicType)) {
                text = getString(R.string.text_en_sentence);
            }
        } else {
            // 中文评测
            if ("read_syllable".equals(topicType)) {
                text = getString(R.string.text_cn_syllable);
            } else if ("read_word".equals(topicType)) {
                text = getString(R.string.text_cn_word);
            } else if ("read_sentence".equals(topicType)) {
                text = getString(R.string.text_cn_sentence);
            }
        }
        mEvaTextEditText.setText(text);
        mResultEditText.setText("");
        mLastResult = null;
        mResultEditText.setHint("请点击“开始评测”按钮");
    }

    private void setParams() {
        // 设置评测语言
        mIse.setParameter(SpeechConstant.LANGUAGE, languageType);
        // 设置需要评测的类型
        mIse.setParameter(SpeechConstant.ISE_CATEGORY, topicType);
        // 设置结果等级(中文仅支持complete)
        mIse.setParameter(SpeechConstant.RESULT_LEVEL, resultLevelType);
        mIse.setParameter(SpeechConstant.TEXT_ENCODING, "utf-8");
        // 设置语音前端点:静音超时时间,即用户多长时间不说话则当做超时处理
        mIse.setParameter(SpeechConstant.VAD_BOS, iseStartTime.getText().toString());
        // 设置语音后端点:后端点静音检测时间,即用户停止说话多长时间内即认为不再输入, 自动停止录音
        mIse.setParameter(SpeechConstant.VAD_EOS, iseEndTime.getText().toString());
        // 语音输入超时时间,即用户最多可以连续说多长时间;(-1无超时)
        mIse.setParameter(SpeechConstant.KEY_SPEECH_TIMEOUT, iseTime.getText().toString());
        mIse.setParameter(SpeechConstant.AUDIO_FORMAT_AUE, "opus");
        // 设置音频保存路径,保存音频格式支持pcm、wav,设置路径为sd卡请注意WRITE_EXTERNAL_STORAGE权限
        mIse.setParameter(SpeechConstant.AUDIO_FORMAT, "wav");
        mIse.setParameter(SpeechConstant.ISE_AUDIO_PATH, Environment.getExternalStorageDirectory().getAbsolutePath() + "/msc/helloword_ise.wav");
        //通过writeaudio方式直接写入音频时才需要此设置
        //mIse.setParameter(SpeechConstant.AUDIO_SOURCE,"-1");
    }

    // 评测监听接口
    private EvaluatorListener mEvaluatorListener = new EvaluatorListener() {
        @Override
        public void onResult(EvaluatorResult result, boolean isLast) {
            Log.e(TAG, "evaluator result :" + isLast);
            if (isLast) {
                StringBuilder builder = new StringBuilder();
                builder.append(result.getResultString());
                if (!TextUtils.isEmpty(builder)) {
                    mResultEditText.setText(builder.toString());
                }
                mIseStartButton.setEnabled(true);
                mLastResult = builder.toString();
                showToast("评测结束");
            }
        }

        @Override
        public void onError(SpeechError error) {
            mIseStartButton.setEnabled(true);
            if (error != null) {
                showToast("error:" + error.getErrorCode() + "," + error.getErrorDescription());
                mResultEditText.setText("");
                mResultEditText.setHint("请点击“开始评测”按钮");
            } else {
                Log.e(TAG, "evaluator over");
            }
        }

        @Override
        public void onBeginOfSpeech() {
            // 此回调表示:sdk内部录音机已经准备好了,用户可以开始语音输入
            Log.e(TAG, "onBeginOfSpeech: evaluator begin");
        }

        @Override
        public void onEndOfSpeech() {
            // 此回调表示:检测到了语音的尾端点,已经进入识别过程,不再接受语音输入
            Log.e(TAG, "onEndOfSpeech: evaluator stoped");
        }

        @Override
        public void onVolumeChanged(int volume, byte[] data) {
            showToast("当前音量:" + volume);
            Log.e(TAG, "onVolumeChanged: 返回音频数据" + data.length);
        }

        @Override
        public void onEvent(int eventType, int arg1, int arg2, Bundle obj) {
            // 以下代码用于获取与云端的会话id,当业务出错时将会话id提供给技术支持人员,可用于查询会话日志,定位出错原因
            //	if (SpeechEvent.EVENT_SESSION_ID == eventType) {
            //		String sid = obj.getString(SpeechEvent.KEY_EVENT_SESSION_ID);
            //		Log.d(TAG, "session id =" + sid);
            //	}
        }
    };

    /**
     * 展示吐司
     */
    private void showToast(final String str) {
        Toast.makeText(this, str, Toast.LENGTH_SHORT).show();
    }

    @Override
    protected void onResume() {
        // 开放统计 移动数据统计分析
        //FlowerCollector.onResume(IseDemo.this);
        //FlowerCollector.onPageStart(TAG);
        super.onResume();
    }

    @Override
    protected void onPause() {
        // 开放统计 移动数据统计分析
        //FlowerCollector.onPageEnd(TAG);
        //FlowerCollector.onPause(IseDemo.this);
        super.onPause();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (null != mIse) {
            mIse.destroy();
            mIse = null;
        }
    }
}

布局文件activity_ise.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center_horizontal"
    android:orientation="vertical"
    android:paddingLeft="10dp"
    android:paddingRight="10dp">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:text="讯飞评测示例"
        android:textSize="30sp" />

    <EditText
        android:id="@+id/ise_eva_text"
        android:layout_width="match_parent"
        android:layout_height="120dp"
        android:layout_marginBottom="5dp"
        android:gravity="top|left"
        android:textSize="20sp" />

    <EditText
        android:id="@+id/ise_result_text"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:gravity="top|left"
        android:hint="请点击“开始评测”按钮"
        android:textSize="16sp" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="10dp"
        android:gravity="center_vertical"
        android:orientation="horizontal">

        <Button
            android:id="@+id/ise_languages"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="语种:汉语"
            android:textSize="16sp" />

        <Button
            android:id="@+id/ise_topic"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="题型:句子"
            android:textSize="16sp" />

        <Button
            android:id="@+id/ise_result_level"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="等级:complete"
            android:textSize="16sp" />

    </LinearLayout>

    <EditText
        android:id="@+id/ise_start_time"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="前端超时:(默认:5000ms)"
        android:inputType="number"
        android:padding="10dp"
        android:textSize="20sp" />

    <EditText
        android:id="@+id/ise_end_time"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="后端超时:(默认:1800ms)"
        android:inputType="number"
        android:padding="10dp"
        android:textSize="20sp" />

    <EditText
        android:id="@+id/ise_time"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="评测超时:(默认:-1无超时,单位同上)"
        android:inputType="number"
        android:padding="10dp"
        android:textSize="20sp" />

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="修改数值后需重新开始评测"
        android:textSize="15sp" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="5dp"
        android:layout_marginBottom="2dp"
        android:gravity="center_horizontal"
        android:orientation="horizontal">

        <Button
            android:id="@+id/ise_start"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="开始评测"
            android:textSize="20sp" />

        <Button
            android:id="@+id/ise_stop"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="停止评测"
            android:textSize="20sp" />
    </LinearLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="10dp"
        android:layout_marginBottom="2dp"
        android:gravity="center_horizontal"
        android:orientation="horizontal">

        <Button
            android:id="@+id/ise_cancel"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="取消评测"
            android:textSize="20sp" />

        <Button
            android:id="@+id/ise_parse"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="结果解析"
            android:textSize="20sp" />
    </LinearLayout>

</LinearLayout>

2、工具类XmlResultParser.java(Demo中也有):

public class XmlResultParser {

    public Result parse(String xml) {
        if (TextUtils.isEmpty(xml)) {
            return null;
        }
        XmlPullParser pullParser = Xml.newPullParser();
        try {
            InputStream ins = new ByteArrayInputStream(xml.getBytes());
            pullParser.setInput(ins, "utf-8");
            FinalResult finalResult = null;

            int eventType = pullParser.getEventType();
            while (XmlPullParser.END_DOCUMENT != eventType) {
                switch (eventType) {
                    case XmlPullParser.START_TAG:
                        if ("FinalResult".equals(pullParser.getName())) {
                            // 只有一个总分的结果
                            finalResult = new FinalResult();
                        } else if ("ret".equals(pullParser.getName())) {
                            finalResult.ret = getInt(pullParser, "value");
                        } else if ("total_score".equals(pullParser.getName())) {
                            finalResult.total_score = getFloat(pullParser, "value");
                        } else if ("xml_result".equals(pullParser.getName())) {
                            // 详细结果
                            return parseResult(pullParser);
                        }
                        break;
                    case XmlPullParser.END_TAG:
                        if ("FinalResult".equals(pullParser.getName())) {
                            return finalResult;
                        }
                        break;
                    default:
                        break;
                }
                eventType = pullParser.next();
            }
        } catch (XmlPullParserException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    private Result parseResult(XmlPullParser pullParser) {
        Result result = null;
        // <rec_paper>标签是否已扫描到
        boolean rec_paperPassed = false;
        Sentence sentence = null;
        Word word = null;
        Syll syll = null;
        Phone phone = null;
        int eventType;
        try {
            eventType = pullParser.getEventType();
            while (XmlPullParser.END_DOCUMENT != eventType) {
                switch (eventType) {
                    case XmlPullParser.START_TAG:
                        if ("rec_paper".equals(pullParser.getName())) {
                            rec_paperPassed = true;
                        } else if ("read_syllable".equals(pullParser.getName())) {
                            if (!rec_paperPassed) {
                                result = new ReadSyllableResult();
                            } else {
                                readTotalResult(result, pullParser);
                            }
                        } else if ("read_word".equals(pullParser.getName())) {
                            if (!rec_paperPassed) {
                                result = new ReadWordResult();
                                String lan = getLanguage(pullParser);
                                result.language = (null == lan) ? "cn" : lan;
                            } else {
                                readTotalResult(result, pullParser);
                            }
                        } else if ("read_sentence".equals(pullParser.getName()) ||
                                "read_chapter".equals(pullParser.getName())) {
                            if (!rec_paperPassed) {
                                result = new ReadSentenceResult();
                                String lan = getLanguage(pullParser);
                                result.language = (null == lan) ? "cn" : lan;
                            } else {
                                readTotalResult(result, pullParser);
                            }
                        } else if ("sentence".equals(pullParser.getName())) {
                            if (null == result.sentences) {
                                result.sentences = new ArrayList<Sentence>();
                            }
                            sentence = createSentence(pullParser);
                        } else if ("word".equals(pullParser.getName())) {
                            if (null != sentence && null == sentence.words) {
                                sentence.words = new ArrayList<Word>();
                            }
                            word = createWord(pullParser);
                        } else if ("syll".equals(pullParser.getName())) {
                            if (null != word && null == word.sylls) {
                                word.sylls = new ArrayList<Syll>();
                            }
                            syll = createSyll(pullParser);
                        } else if ("phone".equals(pullParser.getName())) {
                            if (null != syll && null == syll.phones) {
                                syll.phones = new ArrayList<Phone>();
                            }
                            phone = createPhone(pullParser);
                        }

                        break;
                    case XmlPullParser.END_TAG:
                        if ("phone".equals(pullParser.getName())) {
                            syll.phones.add(phone);
                        } else if ("syll".equals(pullParser.getName())) {
                            word.sylls.add(syll);
                        } else if ("word".equals(pullParser.getName())) {
                            sentence.words.add(word);
                        } else if ("sentence".equals(pullParser.getName())) {
                            result.sentences.add(sentence);
                        } else if ("read_syllable".equals(pullParser.getName())
                                || "read_word".equals(pullParser.getName())
                                || "read_sentence".equals(pullParser.getName())) {
                            return result;
                        }
                        break;
                    default:
                        break;
                }
                eventType = pullParser.next();
            }
        } catch (XmlPullParserException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return result;
    }

    private void readTotalResult(Result result, XmlPullParser pullParser) {
        result.beg_pos = getInt(pullParser, "beg_pos");
        result.end_pos = getInt(pullParser, "end_pos");
        result.content = getContent(pullParser);
        result.total_score = getFloat(pullParser, "total_score");
        result.time_len = getInt(pullParser, "time_len");
        result.except_info = getExceptInfo(pullParser);
        result.is_rejected = getIsRejected(pullParser);
    }

    private Phone createPhone(XmlPullParser pullParser) {
        Phone phone;
        phone = new Phone();
        phone.beg_pos = getInt(pullParser, "beg_pos");
        phone.end_pos = getInt(pullParser, "end_pos");
        phone.content = getContent(pullParser);
        phone.dp_message = getInt(pullParser, "dp_message");
        phone.time_len = getInt(pullParser, "time_len");
        return phone;
    }

    private Syll createSyll(XmlPullParser pullParser) {
        Syll syll;
        syll = new Syll();
        syll.beg_pos = getInt(pullParser, "beg_pos");
        syll.end_pos = getInt(pullParser, "end_pos");
        syll.content = getContent(pullParser);
        syll.symbol = getSymbol(pullParser);
        syll.dp_message = getInt(pullParser, "dp_message");
        syll.time_len = getInt(pullParser, "time_len");
        return syll;
    }

    private Word createWord(XmlPullParser pullParser) {
        Word word;
        word = new Word();
        word.beg_pos = getInt(pullParser, "beg_pos");
        word.end_pos = getInt(pullParser, "end_pos");
        word.content = getContent(pullParser);
        word.symbol = getSymbol(pullParser);
        word.time_len = getInt(pullParser, "time_len");
        word.dp_message = getInt(pullParser, "dp_message");
        word.total_score = getFloat(pullParser, "total_score");
        word.global_index = getInt(pullParser, "global_index");
        word.index = getInt(pullParser, "index");
        return word;
    }

    private Sentence createSentence(XmlPullParser pullParser) {
        Sentence sentence;
        sentence = new Sentence();
        sentence.beg_pos = getInt(pullParser, "beg_pos");
        sentence.end_pos = getInt(pullParser, "end_pos");
        sentence.content = getContent(pullParser);
        sentence.time_len = getInt(pullParser, "time_len");
        sentence.index = getInt(pullParser, "index");
        sentence.word_count = getInt(pullParser, "word_count");
        return sentence;
    }

    private String getLanguage(XmlPullParser pullParser) {
        return pullParser.getAttributeValue(null, "lan");
    }

    private String getExceptInfo(XmlPullParser pullParser) {
        return pullParser.getAttributeValue(null, "except_info");
    }

    private boolean getIsRejected(XmlPullParser pullParser) {
        String isRejected = pullParser.getAttributeValue(null, "is_rejected");
        if (null == isRejected) {
            return false;
        }

        return Boolean.parseBoolean(isRejected);
    }

    private String getSymbol(XmlPullParser pullParser) {
        return pullParser.getAttributeValue(null, "symbol");
    }

    private float getFloat(XmlPullParser pullParser, String attrName) {
        String val = pullParser.getAttributeValue(null, attrName);
        if (null == val) {
            return 0f;
        }
        return Float.parseFloat(val);
    }

    private String getContent(XmlPullParser pullParser) {
        return pullParser.getAttributeValue(null, "content");
    }

    private int getInt(XmlPullParser pullParser, String attrName) {
        String val = pullParser.getAttributeValue(null, attrName);
        if (null == val) {
            return 0;
        }
        return Integer.parseInt(val);
    }
}

将Demo中result文件夹拷贝至项目中,如下图所示:
在这里插入图片描述

3、使用到的strings.xml:

<string name="text_en_word">"[word]\napple\nbanana\norange"</string>
<string name="text_en_sentence">"The quick brown fox jumps over the lazy dog."</string>
<string name="text_cn_syllable">"知,痴,是"</string>
<string name="text_cn_word">"磁铁,率领,脆弱,动手,古筝"</string>
<string name="text_cn_sentence">"一座座雪峰插入云霄,峰顶银光闪闪,大大小小的湖泊,像颗颗宝石镶嵌在彩带般的沟谷中。"</string>

猜你喜欢

转载自blog.csdn.net/qq_34536167/article/details/104657034