Android AudioTrack/AudioRecord-Demo <5>

今天在公司瞎折腾,郁闷死了,吃饱了没事干,写了一个demo程序,用于录取音源原始数据与产品软件音源数据进行比较.参考前面的一些内容:

主程序:

package com.example.audiotrackdemo;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

import android.app.ActionBar;
import android.app.Activity;
import android.media.AudioFormat;
import android.media.AudioRecord;
import android.media.MediaRecorder;
import android.os.Bundle;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnLongClickListener;
import android.view.View.OnTouchListener;
import android.view.WindowManager;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.Spinner;
import android.widget.Toast;

public class AudioRecordAct extends Activity {

    private String TAG = "AudioRecordAct";

    private AudioRecord mAudioRecord;

    private Spinner mDataSpinner;
    private static final String mDataSourceString[] = { "CAMCORDER", "DEFAULT",
            "MIC", "REMOTE_SUBMIX", "VOICE_CALL", "VOICE_COMMUNICATION",
            "VOICE_DOWNLINK", "VOICE_RECOGNITION", "VOICE_UPLINK" };

    private int mDataSourceType;

    private Spinner mDeviceSpinner;
    private static final String mDeviceString[] = { "MIC", "Handset Mic",
            "Headset Mic" };
    private int mDeviceType = 0;

    private Spinner mSampleRateSpinner;
    private static final String mSampleRateString[] = { "44100", "22050",
            "16000", "11025" };

    private int mSampleRateType=44100;

    private Spinner mChannelSpinner;
    private static final String mChannelConfigString[] = { "CHANNEL_IN_MONO",
            "CHANNEL_IN_STEREO", };
    private int mChannelConfigType=AudioFormat.CHANNEL_IN_MONO;

    private Spinner mEncodeSpinner;
    private static final String mAudioEncodeString[] = { "ENCODING_PCM_8BIT",
            "ENCODING_PCM_16BIT" };
    private int mAudioFormatType=AudioFormat.ENCODING_PCM_8BIT;

    private Spinner mBufferSpinner;
    private static final String mBufferSizeString[] = { "AUTO", "512", "1024" };
    private int mBufferSizeType;

    private Button mStartBtn;
    private Button mStopBtn;

    private boolean isRecording;

    @Override
    public void finish() {
        // TODO Auto-generated method stub
        super.finish();

        close();

    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // TODO Auto-generated method stub

        getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
        ActionBar bar = getActionBar();
        bar.setDisplayHomeAsUpEnabled(true);

        super.onCreate(savedInstanceState);
        setContentView(R.layout.audio_rec);
                
        mBufferSizeType=AudioRecord.getMinBufferSize(mSampleRateType, mChannelConfigType, mAudioFormatType);

        mStartBtn = (Button) findViewById(R.id.startrec);
        mStartBtn.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                // TODO Auto-generated method stub
                isRecording = false;
                startRecordAndFile();
            }

        });

        mStopBtn = (Button) findViewById(R.id.stoprec);
        mStopBtn.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                // TODO Auto-generated method stub
                close();
            }

        });

        mDataSpinner = (Spinner) findViewById(R.id.datasrcspinner);
        ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
                android.R.layout.simple_list_item_1, mDataSourceString);
        mDataSpinner.setAdapter(adapter);
        mDataSpinner.setOnItemSelectedListener(new OnItemSelectedListener() {

            @Override
            public void onItemSelected(AdapterView<?> arg0, View arg1,
                    int arg2, long arg3) {
                // TODO Auto-generated method stub
                setDataSource(arg2);
            }

            @Override
            public void onNothingSelected(AdapterView<?> arg0) {
                // TODO Auto-generated method stub

            }

        });

        mDeviceSpinner = (Spinner) findViewById(R.id.devicespinner);
        adapter = new ArrayAdapter<String>(this,
                android.R.layout.simple_list_item_1, mDeviceString);
        mDeviceSpinner.setAdapter(adapter);

        mDeviceSpinner.setOnItemSelectedListener(new OnItemSelectedListener() {

            @Override
            public void onItemSelected(AdapterView<?> arg0, View arg1,
                    int arg2, long arg3) {
                // TODO Auto-generated method stub
                setDevice(arg2);
            }

            @Override
            public void onNothingSelected(AdapterView<?> arg0) {
                // TODO Auto-generated method stub

            }

        });

        mSampleRateSpinner = (Spinner) findViewById(R.id.samplespinner);
        adapter = new ArrayAdapter<String>(this,
                android.R.layout.simple_list_item_1, mSampleRateString);
        mSampleRateSpinner.setAdapter(adapter);
        mSampleRateSpinner
                .setOnItemSelectedListener(new OnItemSelectedListener() {

                    @Override
                    public void onItemSelected(AdapterView<?> arg0, View arg1,
                            int arg2, long arg3) {
                        // TODO Auto-generated method stub
                        setSampleRate(arg2);
                    }

                    @Override
                    public void onNothingSelected(AdapterView<?> arg0) {
                        // TODO Auto-generated method stub

                    }

                });

        mChannelSpinner = (Spinner) findViewById(R.id.channelcfgspinner);
        adapter = new ArrayAdapter<String>(this,
                android.R.layout.simple_list_item_1, mChannelConfigString);
        mChannelSpinner.setAdapter(adapter);
        mChannelSpinner.setOnItemSelectedListener(new OnItemSelectedListener() {

            @Override
            public void onItemSelected(AdapterView<?> arg0, View arg1,
                    int arg2, long arg3) {
                // TODO Auto-generated method stub
                setChannelConfig(arg2);
            }

            @Override
            public void onNothingSelected(AdapterView<?> arg0) {
                // TODO Auto-generated method stub

            }

        });

        mEncodeSpinner = (Spinner) findViewById(R.id.encodespinner);
        adapter = new ArrayAdapter<String>(this,
                android.R.layout.simple_list_item_1, mAudioEncodeString);
        mEncodeSpinner.setAdapter(adapter);

        mEncodeSpinner.setOnItemSelectedListener(new OnItemSelectedListener() {

            @Override
            public void onItemSelected(AdapterView<?> arg0, View arg1,
                    int arg2, long arg3) {
                // TODO Auto-generated method stub
                setAudioFormat(arg2);
            }

            @Override
            public void onNothingSelected(AdapterView<?> arg0) {
                // TODO Auto-generated method stub

            }

        });

        mBufferSpinner = (Spinner) findViewById(R.id.bufferspinner);
        adapter = new ArrayAdapter<String>(this,
                android.R.layout.simple_list_item_1, mBufferSizeString);
        mBufferSpinner.setAdapter(adapter);

        mBufferSpinner.setOnItemSelectedListener(new OnItemSelectedListener() {

            @Override
            public void onItemSelected(AdapterView<?> arg0, View arg1,
                    int arg2, long arg3) {
                // TODO Auto-generated method stub
                setBufferSize(arg2);
                Toast.makeText(
                        AudioRecordAct.this,
                        "mDataSourceType : " + mDataSourceType
                                + " mSampleRateType : " + mSampleRateType
                                + " mChannelConfigType : " + mChannelConfigType
                                + " mAudioFormatType : " + mAudioFormatType
                                + " mBufferSizeType : " + mBufferSizeType,
                        Toast.LENGTH_SHORT).show();

            }

            @Override
            public void onNothingSelected(AdapterView<?> arg0) {
                // TODO Auto-generated method stub

            }

        });

    }

    // AudioName裸音频数据文件 ,麦克风
    private String AudioName = "";
    // NewAudioName可播放的音频文件
    private String NewAudioName = "";

    private void creatAudioRecord() {
        // 获取音频文件路径
        AudioName = getRawFilePath();
        NewAudioName = getWavFilePath();

        if(mBufferSizeType==-2){
            mBufferSizeType=2048;
        }
        mAudioRecord = new AudioRecord(mDataSourceType, mSampleRateType,
                mChannelConfigType, mAudioFormatType, mBufferSizeType);

        Toast.makeText(
                AudioRecordAct.this,
                "mDataSourceType : " + mDataSourceType + " mSampleRateType : "
                        + mSampleRateType + " mChannelConfigType : "
                        + mChannelConfigType + " mAudioFormatType : "
                        + mAudioFormatType + " mBufferSizeType : "
                        + mBufferSizeType, Toast.LENGTH_SHORT).show();

    }

    private void close() {
        if (mAudioRecord != null) {
            System.out.println("stopRecord");
            isRecording = false;// 停止文件写入
            mAudioRecord.stop();
            mAudioRecord.release();// 释放资源
            mAudioRecord = null;
        }
    }

    public int startRecordAndFile() {
        // 判断是否有外部存储设备sdcard
        if (isSdcardExit()) {
            if (isRecording) {
                return 0;
            } else {
                if (mAudioRecord == null) {
                    creatAudioRecord();
                } else {
                    close();
                }

                mAudioRecord.startRecording();
                // 让录制状态为true
                isRecording = true;
                // 开启音频文件写入线程
                new Thread(new AudioRecordThread()).start();

                return 2;
            }

        } else {
            return 1;
        }

    }

    class AudioRecordThread implements Runnable {
        @Override
        public void run() {
            writeDateTOFile();// 往文件中写入裸数据
            copyWaveFile(AudioName, NewAudioName);// 给裸数据加上头文件
        }
    }

    // 这里得到可播放的音频文件
    private void copyWaveFile(String inFilename, String outFilename) {
        FileInputStream in = null;
        FileOutputStream out = null;
        long totalAudioLen = 0;
        long totalDataLen = totalAudioLen + 36;
        long longSampleRate = mSampleRateType;
        int channels = 2;
        long byteRate = 16 * mSampleRateType * channels / 8;
        byte[] data = new byte[mBufferSizeType];
        try {
            in = new FileInputStream(inFilename);
            out = new FileOutputStream(outFilename);
            totalAudioLen = in.getChannel().size();
            totalDataLen = totalAudioLen + 36;
            WriteWaveFileHeader(out, totalAudioLen, totalDataLen,
                    longSampleRate, channels, byteRate);
            while (in.read(data) != -1) {
                out.write(data);
            }
            in.close();
            out.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 这里提供一个头信息。插入这些信息就可以得到可以播放的文件。 为我为啥插入这44个字节,这个还真没深入研究,不过你随便打开一个wav
     * 音频的文件,可以发现前面的头文件可以说基本一样哦。每种格式的文件都有 自己特有的头文件。
     */
    private void WriteWaveFileHeader(FileOutputStream out, long totalAudioLen,
            long totalDataLen, long longSampleRate, int channels, long byteRate)
            throws IOException {
        byte[] header = new byte[44];
        header[0] = 'R'; // RIFF/WAVE header
        header[1] = 'I';
        header[2] = 'F';
        header[3] = 'F';
        header[4] = (byte) (totalDataLen & 0xff);
        header[5] = (byte) ((totalDataLen >> 8) & 0xff);
        header[6] = (byte) ((totalDataLen >> 16) & 0xff);
        header[7] = (byte) ((totalDataLen >> 24) & 0xff);
        header[8] = 'W';
        header[9] = 'A';
        header[10] = 'V';
        header[11] = 'E';
        header[12] = 'f'; // 'fmt ' chunk
        header[13] = 'm';
        header[14] = 't';
        header[15] = ' ';
        header[16] = 16; // 4 bytes: size of 'fmt ' chunk
        header[17] = 0;
        header[18] = 0;
        header[19] = 0;
        header[20] = 1; // format = 1
        header[21] = 0;
        header[22] = (byte) channels;
        header[23] = 0;
        header[24] = (byte) (longSampleRate & 0xff);
        header[25] = (byte) ((longSampleRate >> 8) & 0xff);
        header[26] = (byte) ((longSampleRate >> 16) & 0xff);
        header[27] = (byte) ((longSampleRate >> 24) & 0xff);
        header[28] = (byte) (byteRate & 0xff);
        header[29] = (byte) ((byteRate >> 8) & 0xff);
        header[30] = (byte) ((byteRate >> 16) & 0xff);
        header[31] = (byte) ((byteRate >> 24) & 0xff);
        header[32] = (byte) (2 * 16 / 8); // block align
        header[33] = 0;
        header[34] = 16; // bits per sample
        header[35] = 0;
        header[36] = 'd';
        header[37] = 'a';
        header[38] = 't';
        header[39] = 'a';
        header[40] = (byte) (totalAudioLen & 0xff);
        header[41] = (byte) ((totalAudioLen >> 8) & 0xff);
        header[42] = (byte) ((totalAudioLen >> 16) & 0xff);
        header[43] = (byte) ((totalAudioLen >> 24) & 0xff);
        out.write(header, 0, 44);
    }

    private void writeDateTOFile() {
        // new一个byte数组用来存一些字节数据,大小为缓冲区大小
        byte[] audiodata = new byte[mBufferSizeType];
        FileOutputStream fos = null;
        int readsize = 0;
        try {
            File file = new File(AudioName);
            if (file.exists()) {
                file.delete();
            }
            fos = new FileOutputStream(file);// 建立一个可存取字节的文件
        } catch (Exception e) {
            e.printStackTrace();
        }
        while (isRecording == true) {
            readsize = mAudioRecord.read(audiodata, 0, mBufferSizeType);
            if (AudioRecord.ERROR_INVALID_OPERATION != readsize && fos != null) {
                try {
                    fos.write(audiodata);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        try {
            if (fos != null)
                fos.close();// 关闭写入流
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static boolean isSdcardExit() {
        return android.os.Environment.getExternalStorageState().equals(
                android.os.Environment.MEDIA_MOUNTED);
    }

    public static String getWavFilePath() {
        return "/mnt/sdcard/FinalAudio.wav";
    }

    public static String getRawFilePath() {
//        return "/mnt/sdcard/FinalAudio.amr";
        return "/mnt/sdcard/FinalAudio.raw";
    }

    public static long getFileSize(String file) {
        return (new File(file)).length();
    }

    private void setDevice(int type) {

        switch (type) {

        case 0:
            tools.enterStatus(3);
            break;
        case 1:
            tools.enterStatus(2);
            break;
        case 2:
            tools.enterStatus(1);
            break;
        case 3:
            tools.enterStatus(0);
            break;

        }
    }

    private void setDataSource(int type) {

        switch (type) {

        case 0:
            mDataSourceType = MediaRecorder.AudioSource.CAMCORDER;
            break;
        case 1:
            mDataSourceType = MediaRecorder.AudioSource.DEFAULT;
            break;
        case 2:
            mDataSourceType = MediaRecorder.AudioSource.MIC;
            break;
        case 3:
            mDataSourceType = MediaRecorder.AudioSource.VOICE_CALL;
            break;
        case 4:
            mDataSourceType = MediaRecorder.AudioSource.VOICE_COMMUNICATION;
            break;
        case 5:
            mDataSourceType = MediaRecorder.AudioSource.VOICE_DOWNLINK;
            break;
        case 6:
            mDataSourceType = MediaRecorder.AudioSource.VOICE_RECOGNITION;
            break;
        case 7:
            mDataSourceType = MediaRecorder.AudioSource.VOICE_UPLINK;
            break;
        case 8:
            break;
        default:

        }

    }

    private void setSampleRate(int type) {

        switch (type) {
        case 0:
            mSampleRateType = 44100;
            break;
        case 1:
            mSampleRateType = 22050;
            break;
        case 2:
            mSampleRateType = 16000;
            break;
        case 3:
            mSampleRateType = 11025;
            break;
        }

    }

    private void setChannelConfig(int type) {
        switch (type) {
        case 0:
            mChannelConfigType = AudioFormat.CHANNEL_IN_MONO;
            break;
        case 1:
            mChannelConfigType = AudioFormat.CHANNEL_IN_STEREO;
            break;
        }
    }

    private void setAudioFormat(int type) {

        switch (type) {
        case 0:
            mAudioFormatType = AudioFormat.ENCODING_PCM_8BIT;
            break;
        case 1:
            mAudioFormatType = AudioFormat.ENCODING_PCM_16BIT;
            break;
        case 2:
            mAudioFormatType = AudioFormat.ENCODING_PCM_8BIT;
            break;
        }

    }

    private void setBufferSize(int type) {

        Toast.makeText(
                AudioRecordAct.this,
                "mDataSourceType : " + mDataSourceType + " mSampleRateType : "
                        + mSampleRateType + " mChannelConfigType : "
                        + mChannelConfigType + " mAudioFormatType : "
                        + mAudioFormatType + " mBufferSizeType : "
                        + mBufferSizeType, Toast.LENGTH_SHORT).show();

        switch (type) {
        case 0:
            mBufferSizeType = AudioRecord.getMinBufferSize(mSampleRateType,
                    mChannelConfigType, mAudioFormatType);
            break;
        case 1:
            mBufferSizeType = 512;
            break;

        case 2:
            mBufferSizeType = 1024;
            break;

        }

    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // TODO Auto-generated method stub

        switch (item.getItemId()) { // Respond to the action bar's Up/Home
                                    // button
        case android.R.id.home:
            finish();
            return true;
        }

        return super.onOptionsItemSelected(item);
    }

}

 

xml 文件如下:

<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical" >

        <TextView
            android:id="@+id/textView1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Audio Record :"
            android:textAppearance="?android:attr/textAppearanceLarge" />

        <TextView
            android:id="@+id/textView7"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Mic Device :" />

        <Spinner
            android:id="@+id/devicespinner"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />
        
        <TextView
            android:id="@+id/textView2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Data Source :" />

        <Spinner
            android:id="@+id/datasrcspinner"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />

        <TextView
            android:id="@+id/textView6"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Sample Rate :" />

        <Spinner
            android:id="@+id/samplespinner"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />
        
        <TextView
            android:id="@+id/textView3"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Channel Config :" />

        <Spinner
            android:id="@+id/channelcfgspinner"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />

        <TextView
            android:id="@+id/textView4"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Audio Format :" />

        <Spinner
            android:id="@+id/encodespinner"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />

        <TextView
            android:id="@+id/textView5"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Buffer Size :" />

        <Spinner
            android:id="@+id/bufferspinner"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />

        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent" >

            <Button
                android:id="@+id/startrec"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="start" />

            <Button
                android:id="@+id/stoprec"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_alignParentTop="true"
                android:layout_marginLeft="40dp"
                android:layout_toRightOf="@+id/startrec"
                android:text="stop" />

        </RelativeLayout>
    </LinearLayout>

</ScrollView>

对于Mic Device这一项选择,是本人的,其他的不能使用,可以删除.

 

这个demo可以自由进行参数配置...

 

 

 

 

 

 

 

 

 

 

 

 

转载于:https://www.cnblogs.com/MMLoveMeMM/articles/3687554.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值