每日冲刺4

继续语音功能

复制代码
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true"
    android:orientation="vertical">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">
        <!--标题-->
        <com.google.android.material.appbar.MaterialToolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            android:background="@color/white"
            app:navigationIcon="@mipmap/icon_back">

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="center"
                android:text="语音输入"
                android:textColor="@color/black"
                android:textSize="18sp" />
        </com.google.android.material.appbar.MaterialToolbar>

        <!--列表-->
        <androidx.recyclerview.widget.RecyclerView
            android:id="@+id/rv_result"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:overScrollMode="never"
            android:scrollbars="none" />
    </LinearLayout>

    <!--浮动按钮 语音搜索-->
    <com.google.android.material.floatingactionbutton.FloatingActionButton
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom|end"
        android:layout_margin="@dimen/dp_20"
        android:onClick="voiceInput"
        android:src="@mipmap/icon_voice"
        app:backgroundTint="@color/white"
        app:backgroundTintMode="screen"
        app:fabSize="auto"
        app:hoveredFocusedTranslationZ="@dimen/dp_18"
        app:pressedTranslationZ="@dimen/dp_18" />
</FrameLayout>
复制代码
复制代码
package com.llw.goodtrash.ui;

import android.os.Bundle;
import android.view.View;

import com.google.android.material.appbar.MaterialToolbar;
import com.llw.goodtrash.R;
import com.llw.mvplibrary.base.BaseActivity;

/**
 * 语音输入物品进行垃圾分类
 */
public class VoiceInputActivity extends BaseActivity {

    private MaterialToolbar toolbar;

    @Override
    public void initData(Bundle savedInstanceState) {
        initView();
    }

    private void initView() {
        setStatubar(this, R.color.white, true);
        toolbar = findViewById(R.id.toolbar);
        back(toolbar, false);
    }

    @Override
    public int getLayoutId() {
        return R.layout.activity_voice_input;
    }

    public void voiceInput(View view) {
        showMsg("语音");
    }


}
复制代码
复制代码
    /**
     * 请求权限
     */
    @SuppressLint("CheckResult")
    private void requestPermission() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            //Android6.0及以上版本
            rxPermissions.request(Manifest.permission.RECORD_AUDIO).subscribe(granted -> {
                if (granted) {//权限通过
                    //开始语音监听
                    
                } else {//权限未通过
                    showMsg("权限未通过,你不能使用该功能");
                }
            });
        } else {
            //Android6.0以下无须动态请求
            //开始语音监听
            
        }
    }
复制代码
复制代码
package com.llw.goodtrash.utils;
import org.json.JSONArray;
import org.json.JSONObject;
import org.json.JSONTokener;
/**
 * Json结果解析类
 *
 * @author llw
 * @date 2021/4/1 15:44
 */
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();
    }
}
复制代码
复制代码
package com.llw.goodtrash.utils;

import android.app.Activity;
import android.content.Context;
import android.content.SharedPreferences;
import android.graphics.Paint;
import android.os.Bundle;
import android.os.Environment;
import android.os.MemoryFile;
import android.util.Log;
import android.widget.TextView;
import android.widget.Toast;

import com.iflytek.cloud.ErrorCode;
import com.iflytek.cloud.InitListener;
import com.iflytek.cloud.RecognizerResult;
import com.iflytek.cloud.SpeechConstant;
import com.iflytek.cloud.SpeechError;
import com.iflytek.cloud.SpeechEvent;
import com.iflytek.cloud.SpeechRecognizer;
import com.iflytek.cloud.SpeechSynthesizer;
import com.iflytek.cloud.SynthesizerListener;
import com.iflytek.cloud.msc.util.FileUtil;
import com.iflytek.cloud.msc.util.log.DebugLog;
import com.iflytek.cloud.ui.RecognizerDialog;
import com.iflytek.cloud.ui.RecognizerDialogListener;

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

import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Objects;
import java.util.Vector;

/**
 * 语音工具类
 *
 * @author llw
 */
public class SpeechUtil {

    private static final String TAG = "SpeechUtil";

    private static Context mContext;

    // 语音合成对象
    public static SpeechSynthesizer mTts;

    //播放的文字
    private static String defaultText = "富强、明主、文明、和谐、自由、平等、公正、法制、爱国、敬业、诚信、友善。";


    // 引擎类型
    private static String mEngineType = SpeechConstant.TYPE_CLOUD;

    private static Vector<byte[]> container = new Vector<>();

    //内存文件
    private static MemoryFile memoryFile;
    //总大小
    public static volatile long mTotalSize = 0;


    // 默认发音人
    private static String voicer = "xiaoyan";
    //语速
    private static String speedValue = "50";
    //音调
    private static String pitchValue = "50";
    //音量
    private static String volumeValue = "50";

    private static TextView tvState;

    /****************语音识别********************/

    private static SpeechRecognizer mIat;// 语音听写对象
    private static RecognizerDialog mIatDialog;// 语音听写UI

    // 用HashMap存储听写结果
    private static HashMap<String, String> mIatResults = new LinkedHashMap<String, String>();

    private static SharedPreferences mSharedPreferences;//缓存

    private static String language = "zh_cn";//识别语言

    private static String resultType = "json";//结果内容数据格式

    private static String dictationResults;//听写结果

    /**
     * 初始化监听。
     */
    private static InitListener mTtsInitListener = code -> {
        Log.i(TAG, "InitListener init() code = " + code);
        if (code != ErrorCode.SUCCESS) {
            Log.i(TAG, "初始化失败,错误码:" + code);
        } else {
            Log.i(TAG, "初始化成功");
        }
    };


    /**
     * 初始化
     *
     * @param context
     */
    public static void init(Context context) {
        mContext = context;

        /***************  语音合成 *****************/
        // 初始化合成对象
        mTts = SpeechSynthesizer.createSynthesizer(mContext, mTtsInitListener);


        /***************  语音听写 *****************/
        // 使用SpeechRecognizer对象,可根据回调消息自定义界面;
        mIat = SpeechRecognizer.createRecognizer(mContext, mInitListener);
        // 使用UI听写功能,请根据sdk文件目录下的notice.txt,放置布局文件和图片资源
        mIatDialog = new RecognizerDialog(mContext, mInitListener);
        mSharedPreferences = mContext.getSharedPreferences("ASR",
                Activity.MODE_PRIVATE);
    }

    /**
     * 合成回调监听。
     */
    private static SynthesizerListener mTtsListener = new SynthesizerListener() {
        //开始播放
        @Override
        public void onSpeakBegin() {
            Log.i(TAG, "开始播放");
        }

        //暂停播放
        @Override
        public void onSpeakPaused() {
            Log.i(TAG, "暂停播放");
        }

        //继续播放
        @Override
        public void onSpeakResumed() {
            Log.i(TAG, "继续播放");
        }

        //合成进度
        @Override
        public void onBufferProgress(int percent, int beginPos, int endPos, String info) {
            Log.i(TAG, "合成进度:" + percent + "%");
        }

        //播放进度
        @Override
        public void onSpeakProgress(int percent, int beginPos, int endPos) {
            // 播放进度
            Log.i(TAG, "播放进度:" + percent + "%");
            tvState.setText("播报中");
        }

        //播放完成
        @Override
        public void onCompleted(SpeechError error) {
            tvState.setText("播报完成");
            if (error == null) {
                Log.i(TAG, "播放完成," + container.size());
                DebugLog.LogD("播放完成," + container.size());
                for (int i = 0; i < container.size(); i++) {
                    //写入文件
                    writeToFile(container.get(i));
                }
                //保存文件
                FileUtil.saveFile(memoryFile, mTotalSize, mContext.getExternalFilesDir(null) + "/1.pcm");
            } else {
                //异常信息
                showTip(error.getPlainDescription(true));
            }
            tvState.setText("");
        }

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

            //当设置SpeechConstant.TTS_DATA_NOTIFY为1时,抛出buf数据
            if (SpeechEvent.EVENT_TTS_BUFFER == eventType) {
                byte[] buf = obj.getByteArray(SpeechEvent.KEY_EVENT_TTS_BUFFER);
                Log.i(TAG, "bufis =" + buf.length);
                container.add(buf);
            }
        }
    };

    /**
     * 写入文件
     */
    private static void writeToFile(byte[] data) {
        if (data == null || data.length == 0) {
            return;
        }
        try {
            if (memoryFile == null) {
                Log.i(TAG, "memoryFile is null");
                String mFilepath = mContext.getExternalFilesDir(null) + "/1.pcm";
                memoryFile = new MemoryFile(mFilepath, 1920000);
                memoryFile.allowPurging(false);
            }
            memoryFile.writeBytes(data, 0, (int) mTotalSize, data.length);
            mTotalSize += data.length;
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 参数设置
     *
     * @return
     */
    private static void setParam() {
        // 清空参数
        mTts.setParameter(SpeechConstant.PARAMS, null);
        // 根据合成引擎设置相应参数
        if (mEngineType.equals(SpeechConstant.TYPE_CLOUD)) {
            mTts.setParameter(SpeechConstant.ENGINE_TYPE, SpeechConstant.TYPE_CLOUD);
            //支持实时音频返回,仅在synthesizeToUri条件下支持
            mTts.setParameter(SpeechConstant.TTS_DATA_NOTIFY, "1");

            // 设置在线合成发音人
            mTts.setParameter(SpeechConstant.VOICE_NAME, voicer);
            //设置合成语速
            mTts.setParameter(SpeechConstant.SPEED, speedValue);
            //设置合成音调
            mTts.setParameter(SpeechConstant.PITCH, pitchValue);
            //设置合成音量
            mTts.setParameter(SpeechConstant.VOLUME, volumeValue);
        } else {
            mTts.setParameter(SpeechConstant.ENGINE_TYPE, SpeechConstant.TYPE_LOCAL);
            mTts.setParameter(SpeechConstant.VOICE_NAME, "");
        }
        // 设置播放合成音频打断音乐播放,默认为true
        mTts.setParameter(SpeechConstant.KEY_REQUEST_FOCUS, "false");
        // 设置音频保存路径,保存音频格式支持pcm、wav
        mTts.setParameter(SpeechConstant.AUDIO_FORMAT, "pcm");
        mTts.setParameter(SpeechConstant.TTS_AUDIO_PATH, mContext.getExternalFilesDir(null) + "/msc/tts.pcm");
    }

    /**
     * 开始语音预报
     */
    public static void startVoiceBroadcast(String text, TextView textView) {
        tvState = textView;
        if (mTts == null) {
            showTip("创建对象失败,请确认 libmsc.so 放置正确,且有调用 createUtility 进行初始化");
            return;
        }
        if (text == null || text.isEmpty()) {
            text = defaultText;
        }
        //设置参数
        setParam();
        //开始合成播放
        int code = mTts.startSpeaking(text, mTtsListener);
        if (code != ErrorCode.SUCCESS) {
            showTip("语音合成失败,错误码: " + code);
        }
    }

    /**
     * 初始化语音听写监听器
     */
    private static InitListener mInitListener = code -> {
        Log.d(TAG, "SpeechRecognizer init() code = " + code);
        if (code != ErrorCode.SUCCESS) {
            showTip("初始化失败,错误码:" + code + ",请点击网址https://www.xfyun.cn/document/error-code查询解决方案");
        }
    };


    /**
     * 听写UI监听器
     */
    private static RecognizerDialogListener mRecognizerDialogListener = new RecognizerDialogListener() {
        /**
         * 识别结果
         */
        @Override
        public void onResult(RecognizerResult results, boolean isLast) {

            parsingResult(results);//结果数据解析
        }

        /**
         * 识别回调错误
         */
        @Override
        public void onError(SpeechError error) {
            showTip(error.getPlainDescription(true));
        }

    };

    /**
     * 语音识别结果数据解析
     *
     * @param results
     */
    private static void parsingResult(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();
        }

        mIatResults.put(sn, text);

        StringBuffer resultBuffer = new StringBuffer();
        for (String key : mIatResults.keySet()) {
            resultBuffer.append(mIatResults.get(key));
        }

        dictationResults = resultBuffer.toString();//听写结果显示
        //回调
        mSpeechCallback.dictationResults(dictationResults);

        Log.d(TAG,dictationResults);
    }


    /**
     * 听写参数设置
     *
     * @return
     */
    public static void setDictationParam() {
        // 清空参数
        mIat.setParameter(SpeechConstant.PARAMS, null);
        // 设置听写引擎
        mIat.setParameter(SpeechConstant.ENGINE_TYPE, mEngineType);
        // 设置返回结果格式
        mIat.setParameter(SpeechConstant.RESULT_TYPE, resultType);

        if (language.equals("zh_cn")) {
            String lag = mSharedPreferences.getString("iat_language_preference",
                    "mandarin");
            Log.e(TAG, "language:" + language);// 设置语言
            mIat.setParameter(SpeechConstant.LANGUAGE, "zh_cn");
            // 设置语言区域
            mIat.setParameter(SpeechConstant.ACCENT, lag);
        } else {

            mIat.setParameter(SpeechConstant.LANGUAGE, language);
        }
        Log.e(TAG, "last language:" + mIat.getParameter(SpeechConstant.LANGUAGE));

        //此处用于设置dialog中不显示错误码信息
        //mIat.setParameter("view_tips_plain","false");

        // 设置语音前端点:静音超时时间,即用户多长时间不说话则当做超时处理
        mIat.setParameter(SpeechConstant.VAD_BOS, mSharedPreferences.getString("iat_vadbos_preference", "4000"));

        // 设置语音后端点:后端点静音检测时间,即用户停止说话多长时间内即认为不再输入, 自动停止录音
        mIat.setParameter(SpeechConstant.VAD_EOS, mSharedPreferences.getString("iat_vadeos_preference", "1000"));

        // 设置标点符号,设置为"0"返回结果无标点,设置为"1"返回结果有标点
        mIat.setParameter(SpeechConstant.ASR_PTT, mSharedPreferences.getString("iat_punc_preference", "1"));

        // 设置音频保存路径,保存音频格式支持pcm、wav,设置路径为sd卡请注意WRITE_EXTERNAL_STORAGE权限
        mIat.setParameter(SpeechConstant.AUDIO_FORMAT, "wav");
        mIat.setParameter(SpeechConstant.ASR_AUDIO_PATH, Environment.getExternalStorageDirectory() + "/msc/iat.wav");
    }

    /**
     * 开始听写
     */
    public static void startDictation(SpeechCallback speechCallback){
        mSpeechCallback = speechCallback;
        if( null == mIat ){
            // 创建单例失败,与 21001 错误为同样原因,参考 http://bbs.xfyun.cn/forum.php?mod=viewthread&tid=9688
            showTip( "创建对象失败,请确认 libmsc.so 放置正确,且有调用 createUtility 进行初始化" );
            return;
        }

        mIatResults.clear();//清除数据
        setDictationParam(); // 设置参数
        mIatDialog.setListener(mRecognizerDialogListener);//设置监听

        mIatDialog.show();// 显示对话框

        //获取字体所在的控件
        TextView tvLink = Objects.requireNonNull(mIatDialog.getWindow()).getDecorView().findViewWithTag("textlink");
        tvLink.setText(" ");
        tvLink.getPaint().setFlags(Paint.SUBPIXEL_TEXT_FLAG);//取消下划线
        tvLink.setEnabled(false);//禁用点击
    }

    /**
     * Toast提示
     *
     * @param msg
     */
    private static void showTip(String msg) {
        Toast.makeText(mContext, msg, Toast.LENGTH_SHORT).show();
    }

    //语音回调
    private static SpeechCallback mSpeechCallback;

    /**
     * 语音回调接口
     */
    public interface SpeechCallback {
        /**
         * 听写结果
         */
        void dictationResults(String goodsName);
    }

}
复制代码

 

posted @   摆烂达人  阅读(15)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
点击右上角即可分享
微信分享提示