Android语音录入(MP3格式)-小白无头脑实现

来源:互联网 发布:我的世界mac存档放哪 编辑:程序博客网 时间:2024/05/17 06:29

最近项目开发中要做一个语音提问的功能,在客户端录制MP3格式文件并且上传到服务器端.小白不才,如果下述内容中有任何问题欢迎各位大佬指出,谢谢.

Android中实现录音有三种方式 :

  • 通过意图捕获音频。
  • MediaRecorder类实现录音.
  • AudioRecord录制原始音频.

三种方式的概念,怎么实现网上大佬写了很多我就不班门弄斧了,我的实现方式是通过AudioRecord实现的,先生成RAW格式然后通过工具((com.pocketdigi.utils))转换成MP3格式.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -华丽丽的分割线- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

实现效果 : 录制音频,一般是60秒,录制时间到达50秒时候进入最后10秒倒计时,到达60秒后自动结束录音

这里写图片描述

点击录音开始按钮启动录音功能,同时检测录音的分贝,通过图片展示出来…模仿的就是微信语音那个动画
点击录音暂停按钮结束录音,启动音频文件格式转换

布局文件

<?xml version="1.0" encoding="utf-8"?><RelativeLayout    android:id="@+id/activity_audio_record"    xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="match_parent"    android:layout_height="match_parent">    <Button        android:id="@+id/audio_start"        android:layout_width="match_parent"        android:layout_height="200dp"        android:text="@string/recording_start"/>    <Button        android:id="@+id/audio_stop"        android:layout_width="match_parent"        android:layout_height="200dp"        android:layout_below="@id/audio_start"        android:text="@string/recording_stop"/>    <RelativeLayout        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_below="@id/audio_stop"        android:layout_centerInParent="true"        android:layout_marginTop="10dp"        android:background="@color/cyan5"        android:padding="10dp">        <ImageView            android:id="@+id/aaa"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:src="@mipmap/a9g"/>        <ImageView            android:id="@+id/mic_image"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:layout_toRightOf="@id/aaa"            android:src="@mipmap/tp"/>    </RelativeLayout></RelativeLayout>

图片资源什么的你可以去某些语音APP里面借用一下

录音代码

代码里面都有注释,个人觉得这个注释小白看得懂…所以就不一一解释了

public class AudioRecord extends Activity implements View.OnClickListener, AudioRecorder2Mp3Util.DecibelObserver {    AudioRecorder2Mp3Util util = null;    private boolean canClean = false;//判断是否要清理本地的音频文件    private ImageView mDBImg;//显示语音分贝的View    private Drawable[] micImages; //存储很多张话筒图片的数组    private int maxTime = 60;//语音录入的最大时长    private AudioRecord that;    private final Handler mHandler = new Handler() {        public void handleMessage(android.os.Message msg) {            //当录音进入最后10秒中的时候展现的不再是分贝而是倒计时            //因为分贝很难突破100你用力对着麦克吼一嗓子也就80多一点所以这里处理方式虽然不是很完美,但是可以解决问题            int mTime = msg.arg1;            if (mTime == 900) {                mDBImg.setImageDrawable(micImages[20]);                return;            } else if (mTime == 800) {                mDBImg.setImageDrawable(micImages[19]);                return;            } else if (mTime == 700) {                mDBImg.setImageDrawable(micImages[18]);                return;            } else if (mTime == 600) {                mDBImg.setImageDrawable(micImages[17]);                return;            } else if (mTime == 500) {                mDBImg.setImageDrawable(micImages[16]);                return;            } else if (mTime == 400) {                mDBImg.setImageDrawable(micImages[15]);                return;            } else if (mTime == 300) {                mDBImg.setImageDrawable(micImages[14]);                return;            } else if (mTime == 200) {                mDBImg.setImageDrawable(micImages[13]);                return;            } else if (mTime == 100) {                mDBImg.setImageDrawable(micImages[12]);                return;            } else if (mTime == 1000) {                mDBImg.setImageDrawable(micImages[11]);                //因为录音最大时长是60秒,所以在到达最后一秒的时候就自动结束录音                if (util != null) {                    util.unregisterObserver(that);//注销监听分贝变化                    mHandler.sendEmptyMessage(9);//将声音还原                    util.stopRecordingAndConvertFile();//停止录音并且开始转换                    util.cleanFile(AudioRecorder2Mp3Util.RAW);//清理文件                    // 关闭                    util.close();                    util = null;                }                return;            }            int what = msg.what;            //根据mHandler发送what的大小决定话筒的图片是哪一张            //说话声音越大,发送过来what值越大            if (what > 0) {                if (what >= 0 && what < 10) {                    mDBImg.setImageDrawable(micImages[0]);                } else if (what >= 10 && what < 20) {                    mDBImg.setImageDrawable(micImages[1]);                } else if (what >= 20 && what < 30) {                    mDBImg.setImageDrawable(micImages[2]);                } else if (what >= 30 && what < 40) {                    mDBImg.setImageDrawable(micImages[3]);                } else if (what >= 40 && what < 50) {                    mDBImg.setImageDrawable(micImages[4]);                } else if (what >= 50 && what < 60) {                    mDBImg.setImageDrawable(micImages[5]);                } else if (what >= 60 && what < 70) {                    mDBImg.setImageDrawable(micImages[6]);                } else if (what >= 70 && what < 80) {                    mDBImg.setImageDrawable(micImages[7]);                } else if (what >= 80 && what < 90) {                    mDBImg.setImageDrawable(micImages[8]);                } else if (what >= 90 && what < 100) {                    mDBImg.setImageDrawable(micImages[9]);                } else if (what >= 100) {                    mDBImg.setImageDrawable(micImages[10]);                }            }        }    };    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_audio_record);        findViewById(R.id.audio_start).setOnClickListener(this);        findViewById(R.id.audio_stop).setOnClickListener(this);        mDBImg = (ImageView) findViewById(R.id.mic_image);        // 动画资源文件,用于录制语音时        micImages = new Drawable[]{        //分贝动画图片                getResources().getDrawable(R.mipmap.tp),                getResources().getDrawable(R.mipmap.ts),                getResources().getDrawable(R.mipmap.tt),                getResources().getDrawable(R.mipmap.tu),                getResources().getDrawable(R.mipmap.tv),                getResources().getDrawable(R.mipmap.tw),                getResources().getDrawable(R.mipmap.tx),                getResources().getDrawable(R.mipmap.ty),                getResources().getDrawable(R.mipmap.tz),                getResources().getDrawable(R.mipmap.tq),                getResources().getDrawable(R.mipmap.tr),     //倒计时动画图片                getResources().getDrawable(R.mipmap.akn),                getResources().getDrawable(R.mipmap.ako),                getResources().getDrawable(R.mipmap.akp),                getResources().getDrawable(R.mipmap.akq),                getResources().getDrawable(R.mipmap.akr),                getResources().getDrawable(R.mipmap.aks),                getResources().getDrawable(R.mipmap.akt),                getResources().getDrawable(R.mipmap.aku),                getResources().getDrawable(R.mipmap.akv),                getResources().getDrawable(R.mipmap.akw)        };    }    @Override    public void onClick(View v) {        switch (v.getId()) {            case R.id.audio_start://开始录音                if (util == null) {                        util = new AudioRecorder2Mp3Util(null, SDCardUtils.listAvaliableStorage(this).get(0) + "audiorecorder.raw", SDCardUtils.listAvaliableStorage(this).get(0) + "audiorecorder.mp3");                }                if (canClean) {                    util.cleanFile(AudioRecorder2Mp3Util.MP3 | AudioRecorder2Mp3Util.RAW);                }                Toast.makeText(this, "请说话", Toast.LENGTH_SHORT).show();                maxTime = 60;                util.registerObserver(this);//注册监分贝变化                that = this;                util.startRecording();                startTime();//开始60秒计时                canClean = true;                break;            case R.id.audio_stop://结束录音                if (util != null) {                    util.unregisterObserver(this);//注销监听分贝变化                    mHandler.sendEmptyMessage(9);//将声音还原                    Toast.makeText(this, "正在转换", Toast.LENGTH_SHORT).show();                    util.stopRecordingAndConvertFile();                    util.cleanFile(AudioRecorder2Mp3Util.RAW);                    // 如果要关闭可以                    util.close();                    util = null;                }                break;        }    }    /**     * 分贝放生变化后收到的通知     */    @Override    public void decibelSizeChanged(final int dbSize) {        mHandler.sendEmptyMessage(dbSize);//向handler发送消息做动画操作    }    /**     * 开始自动减时     */    private void startTime() {        final Timer timer = new Timer();        TimerTask task = new TimerTask() {            @Override            public void run() {                Log.i("检查", "倒计时" + maxTime);                maxTime--;                if (maxTime == 9) {//如果倒计时到第九秒就不要在监听分贝变化了,已经不需要在做分贝动画了                    util.unregisterObserver(that);//注销监听分贝变化                }                if (maxTime <= 9) {//到达第九秒后开始发送倒计时消息                    Log.i("检查", "发送消息" + maxTime);                    Message message = new Message();                    message.arg1 = maxTime * 100;//乘以100是让数字足够大 不至于和分贝数值发生冲突                    if (maxTime == 0) {//到达0秒后不在进行计时操作                        timer.cancel();                        message.arg1 = 1000;                        mHandler.sendMessage(message);                        return;                    }                    mHandler.sendMessage(message);                }            }        };        //参数2:1000毫秒之后执行第一次run  参数3:之后每隔1000毫秒执行一次run        timer.schedule(task, 1000, 1000);    }}

音频录制和格式转换

public class AudioRecorder2Mp3Util {    /**     * 构造时候需要的Activity,主要用于获取文件夹的路径     */    private Activity activity;    /**     * 文件代号     */    public static final int RAW = 0X00000001;    public static final int MP3 = 0X00000002;    /**     * 文件路径     */    private String rawPath = null;    private String mp3Path = null;    /**     * 采样频率     */    private static final int SAMPLE_RATE = 8000;    /**     * 录音需要的一些变量     */    private short[] mBuffer;    private AudioRecord mRecorder;    private int bufferSize;    private static ArrayList<DecibelObserver> mObservers = new ArrayList<>();    public AudioRecorder2Mp3Util(Activity activity) {        this.activity = activity;    }    /**     * 录音状态     */    private boolean isRecording = false;    /**     * 是否转换成功     */    private boolean convertOk = false;    /**     * @param activity     * @param rawPath     * @param mp3Path     */    public AudioRecorder2Mp3Util(Activity activity, String rawPath, String mp3Path) {        this.activity = activity;        this.rawPath = rawPath;        this.mp3Path = mp3Path;    }    /**     * 开始录音     */    public boolean startRecording() {        // 如果正在录音,则返回        if (isRecording) {            return isRecording;        }        // 初始化        if (mRecorder == null) {            initRecorder();        }        getFilePath();        mRecorder.startRecording();        startBufferedWrite(new File(rawPath));        isRecording = true;        return isRecording;    }    /**     * 停止录音,并且转换文件,这很可能是个耗时操作,建议在后台中做     */    public boolean stopRecordingAndConvertFile() {        if (!isRecording) {            return isRecording;        }        // 停止        mRecorder.stop();        isRecording = false;        // 开始转换        FLameUtils lameUtils = new FLameUtils(1, SAMPLE_RATE, 96);        convertOk = lameUtils.raw2mp3(rawPath, mp3Path);        return isRecording ^ convertOk;// convertOk==true,return true    }    /**     * 获取文件的路径     *     * @param fileAlias RAW or MP3     * @return     */    public String getFilePath(int fileAlias) {        if (fileAlias == RAW) {            return rawPath;        } else if (fileAlias == MP3) {            return mp3Path;        } else return null;    }    /**     * 清理文件     */    public void cleanFile(int cleanFlag) {        File f = null;        try {            switch (cleanFlag) {                case MP3:                    f = new File(mp3Path);                    if (f.exists()) f.delete();                    break;                case RAW:                    f = new File(rawPath);                    if (f.exists()) f.delete();                    break;                case RAW | MP3:                    f = new File(rawPath);                    if (f.exists()) f.delete();                    f = new File(mp3Path);                    if (f.exists()) f.delete();                    break;            }            f = null;        } catch (Exception e) {            e.printStackTrace();        }    }    /**     * 关闭,可以先调用cleanFile来清理文件     */    public void close() {        if (mRecorder != null) mRecorder.release();        activity = null;    }    // -------内部的一些工具方法-------    /**     * 初始化     */    private void initRecorder() {        bufferSize = AudioRecord.getMinBufferSize(SAMPLE_RATE, AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT);        mBuffer = new short[bufferSize];        mRecorder = new AudioRecord(MediaRecorder.AudioSource.MIC, SAMPLE_RATE, AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT, bufferSize);    }    /**     * 设置路径,第一个为raw文件,第二个为mp3文件     *     * @return     */    private void getFilePath() {        try {            String folder = "audio_recorder_2_mp3";            String fileName = String.valueOf(System.currentTimeMillis());            if (rawPath == null) {                File raw = new File(activity.getDir(folder, activity.MODE_PRIVATE), fileName + ".raw");                raw.createNewFile();                rawPath = raw.getAbsolutePath();                raw = null;            }            if (mp3Path == null) {                File mp3 = new File(activity.getDir(folder, activity.MODE_PRIVATE), fileName + ".mp3");                mp3.createNewFile();                mp3Path = mp3.getAbsolutePath();                mp3 = null;            }            Log.d("rawPath", rawPath);            Log.d("mp3Path", mp3Path);            runCommand("chmod 777 " + rawPath);            runCommand("chmod 777 " + mp3Path);        } catch (Exception e) {            e.printStackTrace();        }    }    /**     * 执行cmd命令,并等待结果     *     * @param command 命令     * @return 是否成功执行     */    private boolean runCommand(String command) {        boolean ret = false;        Process process = null;        try {            process = Runtime.getRuntime().exec(command);            process.waitFor();            ret = true;        } catch (Exception e) {            e.printStackTrace();        } finally {            try {                process.destroy();            } catch (Exception e) {                e.printStackTrace();            }        }        return ret;    }    /**     * 写入到raw文件     *     * @param file     */    private void startBufferedWrite(final File file) {        new Thread(new Runnable() {            @Override            public void run() {                DataOutputStream output = null;                try {                    output = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(file)));                    while (isRecording) {                        int readSize = mRecorder.read(mBuffer, 0, mBuffer.length);                        long v = 0;                        // 将 buffer 内容取出,进行平方和运算                        for (int i = 0; i < mBuffer.length; i++) {                            v += mBuffer[i] * mBuffer[i];                        }                        // 平方和除以数据总长度,得到音量大小。                        double mean = v / (double) readSize;                        double volume = 10 * Math.log10(mean);                        notifySizeChanged((int)volume);                        for (int i = 0; i < readSize; i++) {                            output.writeShort(mBuffer[i]);                        }                    }                } catch (IOException e) {                    e.printStackTrace();                } finally {                    if (output != null) {                        try {                            output.flush();                        } catch (IOException e) {                            e.printStackTrace();                        } finally {                            try {                                output.close();                            } catch (IOException e) {                                e.printStackTrace();                            }                        }                    }                }            }        }).start();    }    /**     * 注册观察者     */    public void registerObserver(DecibelObserver observer) {        if (observer != null) {//不为null并且不存在            mObservers.add(observer);        }    }    /**     * 注销观察者     */    public void unregisterObserver(DecibelObserver observer) {        if (observer != null) {            mObservers.remove(observer);        }    }    /**     * 声音分贝发生变化后通知观察者     */    public void notifySizeChanged(int dbSize) {        for(int i =0; i<mObservers.size(); i++){            mObservers.get(0).decibelSizeChanged(dbSize);        }    }    /**     * 定义观察者接口     */    public interface DecibelObserver{        //录入声音分贝发生变化后通知        public void decibelSizeChanged(int dbSize);    }}

到这里录音所有的代码就完成了…有了音频转换工具的轮子,所以实现起来很简单.如果发现什么问题可以给我留言,谢谢.

0 0
原创粉丝点击