避开Google Voice Search利用Google Speech API实现Android语音识别之Demo实现

来源:互联网 发布:在淘宝开店要交保证金吗 编辑:程序博客网 时间:2024/04/25 21:24

Android语音识别实现:

使用voice search简易实现需要安装google下的语音搜索软件使用科大讯飞需要申请appkey,比较繁琐,后来发现了http://www.google.com/speech-api/v1/recognize?xjerr=1&client=chromium&maxresults=1&lang=zh-CN 这个地址后就产生了想法,于是就有了下面的东西。

一:录音的代码

private void startRecording(){    if (mRecorder == null            || mRecorder.getState() != AudioRecord.STATE_INITIALIZED){        Message msg = mHandler.obtainMessage(MSG_ERROR,ERR_ILLEGAL_STATE,0);        mHandler.sendMessage(msg);        return;    }    mRecorder.startRecording();    if (mRecorder.getRecordingState() == AudioRecord.RECORDSTATE_RECORDING){        textView.setText(R.string.recording);        new Thread(){            @Override            public void run(){                byte[] tmpBuffer = new byte[mBufferSize/2];                while (mRecorder != null                        && mRecorder.getRecordingState() == AudioRecord.RECORDSTATE_RECORDING){                    int numOfRead = mRecorder.read(tmpBuffer,0,tmpBuffer.length);                    if (numOfRead < 0){                        Message msg = mHandler.obtainMessage(MSG_ERROR,ERR_RECORDING,0);                        mHandler.sendMessage(msg);                        break;                    }                    float sum = 0;                    for (int i=0; i < tmpBuffer.length; i+=2){                        short t = (short)(tmpBuffer[i] | (tmpBuffer[i+1] <<8 ));                        sum += Math.abs(t);                    }                    float rms = sum/(tmpBuffer.length * 2);                    Message msg = mHandler.obtainMessage(MSG_RECORD_RECORDING,(int)rms,0);                    mHandler.sendMessage(msg);                    if (mRecordedData.length > mRecordedLength + numOfRead){                        System.arraycopy(tmpBuffer,0,mRecordedData,mRecordedLength,numOfRead);                        mRecordedLength += numOfRead;                    }else {                        break;                    }                }                mHandler.sendEmptyMessage(MSG_RECORD_STOPPED);            }        }.start();    }else {        Message msg = mHandler.obtainMessage(MSG_ERROR,ERR_ILLEGAL_STATE,0);        mHandler.sendMessage(msg);    }}

二:

因为Google的那个网址能识别的格式有限,而PCM又非常容易转化为wav格式的文件,所以下一步就是将录音的数据非常成格式。

从上面可以看到录音的数据我是存放到mRecordedData里面,而mRecordedLength是录音长度,下面是转化为wav格式的代码:

private void createWavHeaderIfNeed(boolean forceCreate){    if (!forceCreate && wavHeader != null){        return;    }    // sample rate * number of channel * bit per sample / bit per bytes    int avgBytesPerSec = mSampleRate * mChannels * DEFAULT_PER_SAMPLE_IN_BIT / 8;    wavHeader = new byte[]{            'R','I','F','F',           //id = RIFF , fixed chars            0, 0, 0, 0,                // RIFF WAVE chunk size = 36 + data length            'W','A','V','E',           //  Type            /* Format chunk */            'f','m','t',' ',          // id = 'fmt '            16, 0, 0, 0,              // format chunk size = 16, if 18, means existing extension message            1, 0,                     // format tag, 0x0001 = 16 pcm            (byte)mChannels, 0, // number of channels (MONO = 1, STEREO =2)            /* 4 bytes , sample rate */            (byte)(mSampleRate & 0xff),            (byte)((mSampleRate >> 8) & 0xff),            (byte)((mSampleRate >> 16) & 0xff),            (byte)((mSampleRate >> 24) & 0xff),            /* 4 bytes average bytes per seconds */            (byte)(avgBytesPerSec & 0xff),            (byte)((avgBytesPerSec >> 8) & 0xff),            (byte)((avgBytesPerSec >> 16) & 0xff),            (byte)((avgBytesPerSec >> 24) & 0xff),            /* 2 bytes, block align */            /******************************             *              sample 1             ******************************             * channel 0 least| channel 0 most|             * ******************************/            (byte)(DEFAULT_PER_SAMPLE_IN_BIT * mChannels / 8), // per sample in bytes            0,            /* 2 bytes, Bits per sample */            16, 0,            /* data chunk */            'd','a','t','a', /// Id = 'data'            0, 0, 0, 0   // data size, set 0 due to unknown yet    };}private void setWavHeaderInt(int offset,int value){    if (offset < 0 || offset > 40){        //total length = 44, int length = 4,        //44 - 4 = 40        throw new IllegalArgumentException("offset out of range");    }    createWavHeaderIfNeed(false);    wavHeader[offset++] = (byte)(value & 0xff);    wavHeader[offset++] = (byte)((value >> 8) & 0xff);    wavHeader[offset++] = (byte)((value >> 16) & 0xff);    wavHeader[offset] = (byte)((value >> 24) & 0xff);}private byte[] getWavData(){    setWavHeaderInt(4,36+mRecordedLength);    setWavHeaderInt(40,mRecordedLength);    byte[] wavData = new byte[44+mRecordedLength];    System.arraycopy(wavHeader,0,wavData,0,wavHeader.length);    System.arraycopy(mRecordedData,0,wavData,wavHeader.length,mRecordedLength);    return wavData;}

三:通过上面的getWavData()就可以获得wav格式的录音数据了。那么接下来就是提交到前面提交的网址上去等待返回的数据了。这一步很简单就是做一个post的工作,代码如下:

private HttpURLConnection getConnection(){    HttpURLConnection connection = null;    try{        URL httpUrl = new URL(GOOGLE_VOICE_API_URL + mLang);        connection = (HttpURLConnection)httpUrl.openConnection();        connection.setConnectTimeout(DEFAULT_CONNECT_TIMEOUT);        connection.setReadTimeout(DEFAULT_READ_TIMEOUT);        connection.setRequestMethod("POST");        connection.setDoInput(true);        connection.setDoOutput(true);        connection.setUseCaches(false);        connection.setRequestProperty("User-Agent",USER_AGENT);        connection.setRequestProperty("Content-Type",CONTENT_TYPE_WAV);    }catch (MalformedURLException ex){        JLog.e(TAG,"getConnection();Invalid url format",ex);    }catch (ProtocolException ex){        JLog.e(TAG, "getConnection();Un support protocol",ex);    }catch (IOException ex){        JLog.e(TAG,"getConnection();IO error while open connection",ex);    }    return connection;}private void startWebRecognizer(final byte[] wavData){    textView.setText(R.string.analyzing);    final HttpURLConnection connection = getConnection();    if (connection == null){        Message msg = mHandler.obtainMessage(MSG_ERROR,ERR_NETWORK,0);        mHandler.sendMessage(msg);    }else {        new Thread(){            @Override            public void run(){                try {                    DataOutputStream dos = new DataOutputStream(connection.getOutputStream());                    dos.write(wavData);                    dos.flush();                    dos.close();                    InputStreamReader inputStreamReader = new InputStreamReader(connection.getInputStream(),                            Charset.forName("utf-8"));                    BufferedReader bufferedReader = new BufferedReader(inputStreamReader);                    StringBuilder sb = new StringBuilder();                    String tmpStr = null;                    while ((tmpStr = bufferedReader.readLine()) != null){                        sb.append(tmpStr);                    }                    Message msg = mHandler.obtainMessage(MSG_DECODE_DATA,sb.toString());                    mHandler.sendMessage(msg);                }catch (IOException ex){                    Message msg = mHandler.obtainMessage(MSG_ERROR,ERR_NETWORK,0);                    mHandler.sendMessage(msg);                }            }        }.start();    }}

四:OK,现在我们获得了返回的数据,那么接着就是解析返回的数据了。首先说明下google返回的数据格式,是如下的json数据:

{      "status":0,    /* 结果代码,0是成功,4是no speech, 5是no match */     "id":"c421dee91abe31d9b8457f2a80ebca91-1",    /* 识别编号 */     "hypotheses":    /* 假设,即结果 */     [          {              "utterance":"下午好",    /* 话语 */             "confidence":0.2507637    /* 信心,即准确度 */         }      ]  }

这里说明下,返回的结果条数是根据前面的maxresults=1来确定的,如果是2就会返回两条,而这些结果是按照准确度从高到低排列的,理论最高值为1.解析结果如下:

private void startParseJson(String jsonString){    try{        JSONObject jsonObject = new JSONObject(jsonString);        int status = jsonObject.getInt("status");        if (status == 0){            JSONArray hypotheses = jsonObject.getJSONArray("hypotheses");            if (hypotheses!= null && hypotheses.length() > 0){                JSONObject hypot = hypotheses.optJSONObject(0);                String speechText = hypot.getString("utterance");                Message msg = mHandler.obtainMessage(MSG_ERROR,ERR_NONE,0,speechText);                mHandler.sendMessage(msg);            }        }else if (status == 4){            Message msg = mHandler.obtainMessage(MSG_ERROR,ERR_NO_SPEECH,0);            mHandler.sendMessage(msg);        }else if (status == 5){            Message msg = mHandler.obtainMessage(MSG_ERROR,ERR_NO_MATCH,0);            mHandler.sendMessage(msg);        }    }catch (JSONException ex){        JLog.e(TAG,"Decode JSON error",ex);        Message msg = mHandler.obtainMessage(MSG_ERROR,ERR_DECODING,0);        mHandler.sendMessage(msg);    }}
这样我们就完成了speech to text的过程就是通常所说的语音识别。下面贴上这个activity的完整代码:

package com.jecofang.catebutler.activities;import android.content.Intent;import android.graphics.drawable.AnimationDrawable;import android.media.AudioFormat;import android.media.AudioRecord;import android.media.MediaRecorder;import android.os.Bundle;import android.os.Handler;import android.os.Message;import android.view.View;import android.widget.ImageView;import android.widget.TextView;import com.jecofang.catebutler.R;import com.jecofang.catebutler.base.BaseActivity;import com.jecofang.catebutler.common.JLog;import org.json.JSONArray;import org.json.JSONException;import org.json.JSONObject;import java.io.BufferedReader;import java.io.DataOutputStream;import java.io.IOException;import java.io.InputStreamReader;import java.net.HttpURLConnection;import java.net.MalformedURLException;import java.net.ProtocolException;import java.net.URL;import java.nio.charset.Charset;/** * *************************************** * File Name : SpeechRecognitionActivity * Author : Jeco Fang * Email : jeco.fang@163.com * Create on : 13-7-19 * All rights reserved 2013 - 2013 * **************************************** */public class SpeechRecognitionActivity extends BaseActivity {    private static final String TAG = "SpeechRecognitionActivity";    /* Recording params */    public static final String AUDIO_SOURCE = "AudioSource";    private static final int DEFAULT_AUDIO_SOURCE = MediaRecorder.AudioSource.VOICE_RECOGNITION;    public static final String SAMPLE_RATE = "SampleRate";    private static final int DEFAULT_SAMPLE_RATE = 16000;    private static final int DEFAULT_AUDIO_ENCODING = AudioFormat.ENCODING_PCM_16BIT;    private static final short DEFAULT_PER_SAMPLE_IN_BYTES = 2;    private static final short DEFAULT_PER_SAMPLE_IN_BIT = 16;    public static final String CHANNELS = "Channels";    private static final short DEFAULT_CHANNELS = 1; //Number of channels (MONO = 1, STEREO = 2)    /* Web API params */    public static final String LANGUAGE = "Language";    private static final String DEFAULT_LANGUAGE = "zh-CN";    private static final String GOOGLE_VOICE_API_URL =            "http://www.google.com/speech-api/v1/recognize?xjerr=1&client=chromium&maxresults=1&lang=";    private static final String USER_AGENT = "Mozilla/5.0";    private static final int DEFAULT_CONNECT_TIMEOUT = 10 * 1000; //10 sec;    private static final int DEFAULT_READ_TIMEOUT = 20 * 1000; //20 sec;    private static final String CONTENT_TYPE_WAV = "audio/L16;rate=16000";    /* Message Types */    private static final int MSG_PREPARE_RECORDER = 1;    private static final int MSG_START_RECORDING = 2;    private static final int MSG_RECORD_RECORDING = 3;    private static final int MSG_STOP_RECORDING = 4;    private static final int MSG_RECORD_STOPPED = 5;    private static final int MSG_DECODE_DATA = 6;    private static final int MSG_ERROR = 7;    /* Errors */    public static final int ERR_NONE = 0;    public static final int ERR_UNKNOWN = -1;    public static final int ERR_UN_SUPPORT_PARAMS = -2;    public static final int ERR_ILLEGAL_STATE = -3;    public static final int ERR_RECORDING = -4;    public static final int ERR_NETWORK = -5;    public static final int ERR_NO_SPEECH = -6;    public static final int ERR_NO_MATCH = -7;    public static final int ERR_DECODING = -8;    private int mSampleRate;    private short mChannels;    private int mAudioSource;    private AudioRecord mRecorder;    private int mBufferSize;    private int mRecordedLength;    private byte[] mRecordedData;    private byte[] wavHeader;    private enum  State{        IDLE,        BUSY    }    private String mLang;    private Handler mHandler = new InternalHandler();    private State mState;    private ImageView imageView;    private TextView textView;    public void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_speech_recognition);        imageView = (ImageView)findViewById(R.id.iv_speaking);        textView = (TextView)findViewById(R.id.tv_result);        mState = State.IDLE;    }    @Override    public void onStart(){        super.onStart();        JLog.d("onStart");        if (mState == State.IDLE){            Intent intent = getIntent();            mAudioSource = intent.getIntExtra(AUDIO_SOURCE,DEFAULT_AUDIO_SOURCE);            mSampleRate = intent.getIntExtra(SAMPLE_RATE,DEFAULT_SAMPLE_RATE);            mChannels = intent.getShortExtra(CHANNELS,DEFAULT_CHANNELS);            mLang = intent.getStringExtra(LANGUAGE);            if (mLang == null || mLang.trim().length() == 0){                mLang = DEFAULT_LANGUAGE;            }            if (!isNetworkAvailable()){                Message message = mHandler.obtainMessage(MSG_ERROR,ERR_NETWORK);                mHandler.sendMessage(message);            }else {                mHandler.sendEmptyMessageDelayed(MSG_PREPARE_RECORDER,500);            }        }    }    @Override    public void onStop(){        super.onStop();        JLog.d("onStop");    }    @Override    public void onPause(){        super.onPause();        JLog.d("onPause");    }    @Override    public void onResume(){        super.onResume();        JLog.d("onResume");    }    private class InternalHandler extends Handler{        private long lastTalkTime;        private long startTime;        AnimationDrawable animationDrawable;        @Override        public void handleMessage(Message msg){            switch (msg.what){                case MSG_PREPARE_RECORDER:                    mState = State.BUSY;                    JLog.d("Prepare recorder");                    prepareRecorder();                    break;                case MSG_START_RECORDING:                    startTime = System.currentTimeMillis();                    lastTalkTime = 0;                    JLog.d("Start recording");                    startRecording();                    textView.setText(R.string.speech);                    break;                case MSG_RECORD_RECORDING:                    //After 5 seconds started recording, if there is no speech, send stop message.                    //In recording if no speech time exclude 3 seconds, send stop message                    long currentTime = System.currentTimeMillis();                    int volume = msg.arg1;                    JLog.d(TAG,"Record recording.Volume = %d",volume );                    if (lastTalkTime == 0){                        if (volume >= 30){                            lastTalkTime = currentTime;                            startAnimationIfNeed(animationDrawable);                        }else {                            stopAnimation(animationDrawable);                            if (currentTime - startTime >= 5 * 1000){                                mHandler.sendEmptyMessage(MSG_STOP_RECORDING);                            }                        }                    }else {                        if (volume >= 30){                            lastTalkTime = currentTime;                            startAnimationIfNeed(animationDrawable);                        }else {                            stopAnimation(animationDrawable);                            if (currentTime - lastTalkTime >= 3 * 1000){                                mHandler.sendEmptyMessage(MSG_STOP_RECORDING);                            }                        }                    }                    break;                case MSG_STOP_RECORDING:                    JLog.d("Stop recording");                    stopAnimation(animationDrawable);                    stopRecording();                    break;                case MSG_RECORD_STOPPED:                    JLog.d("Recorder stopped, try to get remote data");                    byte[] wavData = getWavData();                    startWebRecognizer(wavData);                    if (mRecorder != null){                        mRecorder.release();                        mRecorder = null;                    }                    break;                case MSG_DECODE_DATA:                    String data = "";                    if (msg.obj != null){                        data = msg.obj.toString();                    }                    JLog.d("Try to parse data :" + data);                    if (data.trim().length()> 0){                        startParseJson(data.trim());                    }else {                        Message message = mHandler.obtainMessage(MSG_ERROR,ERR_UNKNOWN,0);                        mHandler.sendMessage(message);                    }                    break;                case MSG_ERROR:                    mState = State.IDLE;                    if (mRecorder != null){                        mRecorder.release();                        mRecorder = null;                    }                    Intent intent = new Intent();                    intent.putExtra(SPEECH_RESULT_STATUS,msg.arg1);                    if (msg.obj != null){                        JLog.d("Error:"+msg.arg1+";value"+msg.obj);                        intent.putExtra(SPEECH_RESULT_VALUE,msg.obj.toString());                    }                    JLog.d("Error:"+msg.arg1);                    setResult(RESULT_OK,intent);                    finish();                    break;                default:                    break;            }        }    }    private void prepareRecorder(){        int minBufferSize = AudioRecord.getMinBufferSize(mSampleRate,                AudioFormat.CHANNEL_IN_MONO,DEFAULT_AUDIO_ENCODING);        if (minBufferSize == AudioRecord.ERROR_BAD_VALUE){            JLog.e(TAG, "Params are not support by hardware.n"                    + "sample rate: %d; channel: %2x; encoding: %2x",                    mSampleRate,                    AudioFormat.CHANNEL_IN_MONO,                    DEFAULT_AUDIO_ENCODING);            Message msg = mHandler.obtainMessage(MSG_ERROR,ERR_UN_SUPPORT_PARAMS,0);            mHandler.sendMessage(msg);            return;        }else if (minBufferSize == AudioRecord.ERROR){            JLog.w(TAG,"Unable to query hardware for output property");            minBufferSize = mSampleRate * (120 / 1000) * DEFAULT_PER_SAMPLE_IN_BYTES * mChannels;        }        mBufferSize = minBufferSize * 2;        mRecorder = new AudioRecord(mAudioSource,mSampleRate,                AudioFormat.CHANNEL_IN_MONO,DEFAULT_AUDIO_ENCODING,mBufferSize);        if (mRecorder.getState() != AudioRecord.STATE_INITIALIZED){            JLog.e(TAG,"AudioRecord initialize failed");            Message msg = mHandler.obtainMessage(MSG_ERROR,ERR_ILLEGAL_STATE,0);            mHandler.sendMessage(msg);            return;        }        mRecordedLength = 0;        int maxRecordLength = mSampleRate * mChannels * DEFAULT_PER_SAMPLE_IN_BYTES * 35;        mRecordedData = new byte[maxRecordLength];        Message msg = mHandler.obtainMessage(MSG_START_RECORDING);        mHandler.sendMessage(msg);    }    private void startRecording(){        if (mRecorder == null                || mRecorder.getState() != AudioRecord.STATE_INITIALIZED){            Message msg = mHandler.obtainMessage(MSG_ERROR,ERR_ILLEGAL_STATE,0);            mHandler.sendMessage(msg);            return;        }        mRecorder.startRecording();        if (mRecorder.getRecordingState() == AudioRecord.RECORDSTATE_RECORDING){            textView.setText(R.string.recording);            new Thread(){                @Override                public void run(){                    byte[] tmpBuffer = new byte[mBufferSize/2];                    while (mRecorder != null                            && mRecorder.getRecordingState() == AudioRecord.RECORDSTATE_RECORDING){                        int numOfRead = mRecorder.read(tmpBuffer,0,tmpBuffer.length);                        if (numOfRead < 0){                            Message msg = mHandler.obtainMessage(MSG_ERROR,ERR_RECORDING,0);                            mHandler.sendMessage(msg);                            break;                        }                        float sum = 0;                        for (int i=0; i < tmpBuffer.length; i+=2){                            short t = (short)(tmpBuffer[i] | (tmpBuffer[i+1] <<8 ));                            sum += Math.abs(t);                        }                        float rms = sum/(tmpBuffer.length * 2);                        Message msg = mHandler.obtainMessage(MSG_RECORD_RECORDING,(int)rms,0);                        mHandler.sendMessage(msg);                        if (mRecordedData.length > mRecordedLength + numOfRead){                            System.arraycopy(tmpBuffer,0,mRecordedData,mRecordedLength,numOfRead);                            mRecordedLength += numOfRead;                        }else {                            break;                        }                    }                    mHandler.sendEmptyMessage(MSG_RECORD_STOPPED);                }            }.start();        }else {            Message msg = mHandler.obtainMessage(MSG_ERROR,ERR_ILLEGAL_STATE,0);            mHandler.sendMessage(msg);        }    }    private void stopRecording(){        if (mRecorder != null                && mRecorder.getRecordingState() == AudioRecord.RECORDSTATE_RECORDING){            mRecorder.stop();        }    }    private void createWavHeaderIfNeed(boolean forceCreate){        if (!forceCreate && wavHeader != null){            return;        }        // sample rate * number of channel * bit per sample / bit per bytes        int avgBytesPerSec = mSampleRate * mChannels * DEFAULT_PER_SAMPLE_IN_BIT / 8;        wavHeader = new byte[]{                'R','I','F','F',           //id = RIFF , fixed chars                0, 0, 0, 0,                // RIFF WAVE chunk size = 36 + data length                'W','A','V','E',           //  Type                /* Format chunk */                'f','m','t',' ',          // id = 'fmt '                16, 0, 0, 0,              // format chunk size = 16, if 18, means existing extension message                1, 0,                     // format tag, 0x0001 = 16 pcm                (byte)mChannels, 0, // number of channels (MONO = 1, STEREO =2)                /* 4 bytes , sample rate */                (byte)(mSampleRate & 0xff),                (byte)((mSampleRate >> 8) & 0xff),                (byte)((mSampleRate >> 16) & 0xff),                (byte)((mSampleRate >> 24) & 0xff),                /* 4 bytes average bytes per seconds */                (byte)(avgBytesPerSec & 0xff),                (byte)((avgBytesPerSec >> 8) & 0xff),                (byte)((avgBytesPerSec >> 16) & 0xff),                (byte)((avgBytesPerSec >> 24) & 0xff),                /* 2 bytes, block align */                /******************************                 *              sample 1                 ******************************                 * channel 0 least| channel 0 most|                 * ******************************/                (byte)(DEFAULT_PER_SAMPLE_IN_BIT * mChannels / 8), // per sample in bytes                0,                /* 2 bytes, Bits per sample */                16, 0,                /* data chunk */                'd','a','t','a', /// Id = 'data'                0, 0, 0, 0   // data size, set 0 due to unknown yet        };    }    private void setWavHeaderInt(int offset,int value){        if (offset < 0 || offset > 40){            //total length = 44, int length = 4,            //44 - 4 = 40            throw new IllegalArgumentException("offset out of range");        }        createWavHeaderIfNeed(false);        wavHeader[offset++] = (byte)(value & 0xff);        wavHeader[offset++] = (byte)((value >> 8) & 0xff);        wavHeader[offset++] = (byte)((value >> 16) & 0xff);        wavHeader[offset] = (byte)((value >> 24) & 0xff);    }    private byte[] getWavData(){        setWavHeaderInt(4,36+mRecordedLength);        setWavHeaderInt(40,mRecordedLength);        byte[] wavData = new byte[44+mRecordedLength];        System.arraycopy(wavHeader,0,wavData,0,wavHeader.length);        System.arraycopy(mRecordedData,0,wavData,wavHeader.length,mRecordedLength);        return wavData;    }    private HttpURLConnection getConnection(){        HttpURLConnection connection = null;        try{            URL httpUrl = new URL(GOOGLE_VOICE_API_URL + mLang);            connection = (HttpURLConnection)httpUrl.openConnection();            connection.setConnectTimeout(DEFAULT_CONNECT_TIMEOUT);            connection.setReadTimeout(DEFAULT_READ_TIMEOUT);            connection.setRequestMethod("POST");            connection.setDoInput(true);            connection.setDoOutput(true);            connection.setUseCaches(false);            connection.setRequestProperty("User-Agent",USER_AGENT);            connection.setRequestProperty("Content-Type",CONTENT_TYPE_WAV);        }catch (MalformedURLException ex){            JLog.e(TAG,"getConnection();Invalid url format",ex);        }catch (ProtocolException ex){            JLog.e(TAG, "getConnection();Un support protocol",ex);        }catch (IOException ex){            JLog.e(TAG,"getConnection();IO error while open connection",ex);        }        return connection;    }    private void startWebRecognizer(final byte[] wavData){        textView.setText(R.string.analyzing);        final HttpURLConnection connection = getConnection();        if (connection == null){            Message msg = mHandler.obtainMessage(MSG_ERROR,ERR_NETWORK,0);            mHandler.sendMessage(msg);        }else {            new Thread(){                @Override                public void run(){                    try {                        DataOutputStream dos = new DataOutputStream(connection.getOutputStream());                        dos.write(wavData);                        dos.flush();                        dos.close();                        InputStreamReader inputStreamReader = new InputStreamReader(connection.getInputStream(),                                Charset.forName("utf-8"));                        BufferedReader bufferedReader = new BufferedReader(inputStreamReader);                        StringBuilder sb = new StringBuilder();                        String tmpStr = null;                        while ((tmpStr = bufferedReader.readLine()) != null){                            sb.append(tmpStr);                        }                        Message msg = mHandler.obtainMessage(MSG_DECODE_DATA,sb.toString());                        mHandler.sendMessage(msg);                    }catch (IOException ex){                        Message msg = mHandler.obtainMessage(MSG_ERROR,ERR_NETWORK,0);                        mHandler.sendMessage(msg);                    }                }            }.start();        }    }    private void startParseJson(String jsonString){        try{            JSONObject jsonObject = new JSONObject(jsonString);            int status = jsonObject.getInt("status");            if (status == 0){                JSONArray hypotheses = jsonObject.getJSONArray("hypotheses");                if (hypotheses!= null && hypotheses.length() > 0){                    JSONObject hypot = hypotheses.optJSONObject(0);                    String speechText = hypot.getString("utterance");                    Message msg = mHandler.obtainMessage(MSG_ERROR,ERR_NONE,0,speechText);                    mHandler.sendMessage(msg);                }            }else if (status == 4){                Message msg = mHandler.obtainMessage(MSG_ERROR,ERR_NO_SPEECH,0);                mHandler.sendMessage(msg);            }else if (status == 5){                Message msg = mHandler.obtainMessage(MSG_ERROR,ERR_NO_MATCH,0);                mHandler.sendMessage(msg);            }        }catch (JSONException ex){            JLog.e(TAG,"Decode JSON error",ex);            Message msg = mHandler.obtainMessage(MSG_ERROR,ERR_DECODING,0);            mHandler.sendMessage(msg);        }    }    private void startAnimationIfNeed(AnimationDrawable animationDrawable){        imageView.setVisibility(View.VISIBLE);        if (animationDrawable == null){            imageView.setBackgroundResource(R.anim.speak_view);            animationDrawable = (AnimationDrawable)imageView.getBackground();        }        if (animationDrawable != null && !animationDrawable.isRunning()){            animationDrawable.start();        }    }    private void stopAnimation(AnimationDrawable animationDrawable){        imageView.setVisibility(View.INVISIBLE);    }}

必须说一句的就是里面的JLog.x是自己简单封装了下Log的类,主要是统一控制log level。BaseActivity是activity的一些常用方法的封装以及自定义的一些常量,这里用的只有几个常量:
protected static final int GET_SPEECH_RESULT = 1;protected static final String SPEECH_RESULT_STATUS = "speechResultStatus";protected static final String SPEECH_RESULT_VALUE = "speechResultValue";
layout文件代码:

<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"                android:layout_width="fill_parent"                android:layout_height="fill_parent"        android:background="#90000000">    <RelativeLayout            android:layout_width="fill_parent"            android:layout_height="wrap_content"            android:layout_centerInParent="true">        <LinearLayout                android:layout_width="240dp"                android:layout_height="wrap_content"                android:orientation="vertical"                android:layout_centerHorizontal="true">        </LinearLayout>    </RelativeLayout>    <RelativeLayout            android:id="@+id/image_layout"            android:layout_height="230dp"            android:layout_width="230dp"            android:layout_centerInParent="true">        <ImageView                android:id="@+id/iv_speaking"                android:layout_height="wrap_content"                android:layout_width="wrap_content"                android:layout_centerInParent="true">        </ImageView>        <ImageView                android:layout_height="wrap_content"                android:layout_width="wrap_content"                android:layout_centerInParent="true"                android:background="@drawable/ic_speech">        </ImageView>        <TextView                android:id="@+id/tv_result"                android:layout_height="wrap_content"                android:layout_width="wrap_content"                android:textColor="#FFFFFFFF"                android:textSize="14sp"                android:singleLine="true"                android:ellipsize="marquee"                android:marqueeRepeatLimit="marquee_forever"                android:layout_marginTop="40dip"                android:layout_centerInParent="true">        </TextView>    </RelativeLayout></RelativeLayout>

整个layout的背景是设置的#90000000,就是黑色的半透明。

speak animation的代码:

<?xml version="1.0" encoding="utf-8"?><animation-list android:oneshot="false"                xmlns:android="http://schemas.android.com/apk/res/android">    <item android:duration="150" android:drawable="@drawable/mic_1" />    <item android:duration="150" android:drawable="@drawable/mic_2" />    <item android:duration="150" android:drawable="@drawable/mic_3" />    <item android:duration="150" android:drawable="@drawable/mic_4" /></animation-list>

其实就是几张半透明的从小到大的圆圈。

至于调用就很简单了:

ib_Speak = (ImageButton)findViewById(R.id.main_bottom_bar_ib_speak);       ib_Speak.setOnClickListener(new View.OnClickListener() {           @Override           public void onClick(View view) {               Intent intent = new Intent(MainActivity.this,SpeechRecognitionActivity.class);               startActivityForResult(intent, GET_SPEECH_RESULT);               //Intent intent = new Intent(MainActivity.this,Record.class);               //startActivity(intent);           }       });

获取结果:

@Overrideprotected void onActivityResult(int requestCode, int resultCode, Intent data){    if (requestCode == GET_SPEECH_RESULT){        if (resultCode == RESULT_CANCELED){            //do nothing for now        }else if (resultCode == RESULT_OK){            JLog.i("status;"+ data.getIntExtra(SPEECH_RESULT_STATUS,0));            switch (data.getIntExtra(SPEECH_RESULT_STATUS,0)){                case SpeechRecognitionActivity.ERR_NONE:                    String text = data.getStringExtra(SPEECH_RESULT_VALUE);                    if (text != null && text.trim().length() > 0){                        submitText(text);                    }                    break;                default:                    Toast.makeText(this,R.string.error,Toast.LENGTH_SHORT).show();                    break;            }        }    }}








0 0