VoiceTranslation项目解析

作者: tuionf | 来源:发表于2017-03-29 14:53 被阅读223次

    Github的地址—VoiceTranslation项目

    功能

    • 英文翻译成中文
    • 英文语音翻译
    • 翻译时没有网络的提示

    实现

    思路

    整体思路

    1. 使用 AsyncTask 发起网络请求
      • .doInBackground 做真正的后台网络请求
      • onPostExecute 对返回的结果作处理
    2. 利用接口将请求的数据(翻译的结果)返回给 UI

    翻译模块

    翻译使用有道翻译 的 API,参考 http://fanyi.youdao.com/openapi?path=data-mode

    1. 通过网址拼接的形式来获取翻译的数据
    2. http://fanyi.youdao.com/openapi.do?keyfrom=<keyfrom>&key=<key>&type=data&doctype=<doctype>&version=1.1&q=要翻译的文本
    3. 需要修改的地方
      1. key需要替换为自己申请的key ;
      2. doctype - 返回结果的数据格式,xml或json或jsonp,此处是json
    4. 返回码errorCode是0 的时候表示 正常

    讯飞语音接口

    1. 下载相应的SDK,集成到项目中
    2. 根据文档 http://www.xfyun.cn/doccenter/awd 调用接口

    关键点

    网络请求

    AsyncTask

    AsyncTask的三个参数,

    • Params 启动任务执行的输入参数,比如HTTP请求的URL————决定了doInBackground方法、execute方法的参数类型
    • Progress 后台任务执行的百分比————决定了publishProgress方法、onProgressUpdate方法的参数类型
    • Result 后台执行任务最终返回的结果,比如String,Integer等————决定了doInBackground方法的返回值类型、onPostExecute方法的参数类型

    不需要参数可以传 void,此处 doInBackground方法 执行后台翻译的网络请求,所以参数类型是 String ,返回的结果也是 String 类型,在onPostExecute中处理返回的结果,第二个参数百分比目前不需要,设置为void

    HttpURLConnection

    //执行网络请求
                URL url = null;
                HttpURLConnection httpURLConnection = null;
                BufferedReader reader = null;
                StringBuilder response = new StringBuilder();
    
                try {
                    url = new URL(params[0]);
    
                    Log.e(TAG,"网络请求链接-----"+url.toString());
    
                    httpURLConnection = (HttpURLConnection) url.openConnection();
                    httpURLConnection.setRequestMethod("GET");
                    httpURLConnection.setConnectTimeout(5000);
                    httpURLConnection.setReadTimeout(5000);
    
                    InputStream is = httpURLConnection.getInputStream();
                    reader = new BufferedReader(new InputStreamReader(is));
    
                    Log.e(TAG,"网络请求-----"+httpURLConnection.getResponseCode());
    
                    String line ;
                    while ((line = reader.readLine()) != null){
                        response.append(line);
                    }
    
                } catch (Exception e) {
                    e.printStackTrace();
                }finally {
                    if (reader != null) {
                        try {
                            reader.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
    
                    if (httpURLConnection != null) {
                        httpURLConnection.disconnect();
                    }
    

    请求结果与UI交互

    onPostExecute中来处理返回的结果
    与UI交互,利用接口

    @Override
            protected void onPostExecute(String s) {
                super.onPostExecute(s);
                if (s != null) {
                    onResponseListener.onSuccess(s);
                }
            }
    

    回调接口

    public interface onResponseListener{
            void onSuccess(String result);
            void onFail(String error);
        }
    

    网络请求实例写成单例

    public static HttpUtil getInstance() {
            if (mHttpUtil == null) {
                synchronized (HttpUtil.class){
                    if (mHttpUtil == null) {
                        mHttpUtil = new HttpUtil();
                    }
                }
            }
            return mHttpUtil;
        }
    

    语音识别

    初始化

    1. 在OnCreate方法中初始化
    SpeechUtility.createUtility(context, SpeechConstant.APPID +"=APPID");   
    
    1. 创建SpeechRecognizer对象
    SpeechRecognizer mIat = SpeechRecognizer.createRecognizer(MainActivity.this,mInitListener);
    
        /**
         * 初始化监听器。
         */
        private InitListener mInitListener = new InitListener() {
    
            @Override
            public void onInit(int code) {
    
                if (code != ErrorCode.SUCCESS) {
                    Toast.makeText(MainActivity.this, "初始化失败,错误码:" + code, Toast.LENGTH_SHORT).show();
                }
            }
        };
    
    1. 设置参数
    public void setParam() {
            // 清空参数
            mIat.setParameter(SpeechConstant.PARAMS, null);
    
            // 设置听写引擎
            mIat.setParameter(SpeechConstant.ENGINE_TYPE, mEngineType);
            // 设置返回结果格式
            mIat.setParameter(SpeechConstant.RESULT_TYPE, "json");
            // 设置语言
            mIat.setParameter(SpeechConstant.LANGUAGE, "en_us");
            // 设置音频保存路径,保存音频格式支持pcm、wav,设置路径为sd卡请注意WRITE_EXTERNAL_STORAGE权限
            // 注:AUDIO_FORMAT参数语记需要更新版本才能生效
            mIat.setParameter(SpeechConstant.AUDIO_FORMAT,"wav");
            mIat.setParameter(SpeechConstant.ASR_AUDIO_PATH, Environment.getExternalStorageDirectory()+"/msc/iat.wav");
        }
    

    4.开始听写

    mIat.startListening(mRecoListener);  
    

    听写回调

    • 听写结果回调接口(返回Json格式结果
    • 一般情况下会通过onResults接口多次返回结果,完整的识别内容是多次结果的累加;
    • 关于解析Json的代码可参见MscDemo中JsonParser类;
    • isLast等于true时会话结束
    private RecognizerListener mRecoListener = new RecognizerListener() {
            //音量值0~30
            @Override
            public void onVolumeChanged(int i, byte[] bytes) {
    //            Toast.makeText(MainActivity.this, "音量:" + i, Toast.LENGTH_SHORT).show();
            }
    
            //开始录音
            @Override
            public void onBeginOfSpeech() {
    //            Toast.makeText(MainActivity.this, "开始录音" , Toast.LENGTH_SHORT).show();
            }
    
            //结束录音
            @Override
            public void onEndOfSpeech() {
    //            Toast.makeText(MainActivity.this, "结束录音" , Toast.LENGTH_SHORT).show();
                mIatDialog.dismiss();
            }
    
            //一般情况下会通过onResults接口多次返回结果,完整的识别内容是多次结果的累加
            @Override
            public void onResult(RecognizerResult recognizerResult, boolean isLast) {
                printResult(recognizerResult);
                Log.d("Result:",recognizerResult.getResultString ());
            }
    
            //会话发生错误回调接口
            @Override
            public void onError(SpeechError speechError) {
            }
    
            //扩展用接口
            @Override
            public void onEvent(int i, int i1, int i2, Bundle bundle) {
    
            }
        };
    
    

    语音返回数据处理

    数据格式-json

    enter description hereenter description here enter description hereenter description here
    1. 分析数据结构

    需要的数据在 ws 这个array下,先去这个array

    JSONArray words = joResult.getJSONArray("ws");
    
    enter description hereenter description here
    1. ws的目录结构
      取ws这个array 里面的第一个值
    enter description hereenter description here
    words.getJSONObject(i)
    

    3.ws下第一个jsonobject的结构

    enter description hereenter description here

    取 cw这个数组

    JSONArray items = words.getJSONObject(i).getJSONArray("cw");
    
    1. cw 这个数组的结构


      enter description hereenter description here

      取第一个值

    JSONObject obj = items.getJSONObject(0);
    
    enter description hereenter description here

    取 key为 w 的值

    obj.getString("w")
    

    坑。。。

    导包 jar 和 so文件

    导包 jar

    enter description hereenter description here
    1. 按照上图创建libs目录
    2. 拷贝jar包到libs下
    3. 选中jar包,右键
    enter description hereenter description here
    1. enter description hereenter description here

    添加so文件

    enter description hereenter description here
    1. 建立目录jniLibs
    2. 拷贝so文件进去
    3. 在该目录 enter description hereenter description here

      中的android添加
      sourceSets { main { jni.srcDirs = ['src/main/jni', 'src/main/jniLibs'] }

    android {
        compileSdkVersion 25
        buildToolsVersion "25.0.2"
         .....
        sourceSets { main { jni.srcDirs = ['src/main/jni', 'src/main/jniLibs'] } }
    }
    

    网络权限

    开发过程中,打包完成之后讯飞在录音时报错,进行排查

    1. 检查需要的录音权限是否申请——已申请
    2. 检查是否有其他程序占用麦克风——无
    3. 重启手机——重启之后还是不行

    最后发现应用安装在手机上之后手机没有给应用权限

    小技巧

    快捷键

    Ctrl+F3 跳转到下一个相同变量——向下搜索
    Shift+F3 跳转到上一个相同变量——向上搜索
    Ctrl+F12 查看类中所有的参数和方法

    每次设置参数或者给Edittext内容之前都应该先清空内容

    第三方引入的库中对象的初始化在使用前应该首先判断是否为空,并弹框提示,方便定位问题。

    if( null == mIat )
    { // 创建单例失败
              Toast.makeText(this, "创建对象失败,请确认 libmsc.so 放置正确,且有调用 createUtility 进行初始化" , Toast.LENGTH_SHORT).show();
             return;
     }
    

    相关文章

      网友评论

        本文标题:VoiceTranslation项目解析

        本文链接:https://www.haomeiwen.com/subject/cmneottx.html