使用 AudioRecord 录音

Audio recording using AudioRecord

我决定使用 AudioRecord 而不是 MediaRecorder 来录制音频,以达到最高质量。问题是,该应用程序由于某种原因无法运行。有 2 个按钮:录制和播放,录制用于开始和停止录制(使用新线程),播放应该使用 MediaPlayer 播放文件。

代码:

    public class MyActivity extends Activity {

    AudioRecord recorder = null;
    int SAMPLE_RATE = 44100;
    int ENCODING = AudioFormat.ENCODING_PCM_16BIT;
    int SOURCE = MediaRecorder.AudioSource.MIC;
    int CONFIG = AudioFormat.CHANNEL_IN_MONO;
    int BUFFER_SIZE;
    boolean isRecording = false;
    boolean isPlaying = false;
    String currentFileDir;
    byte[] b;
    File file;
    OutputStream FOS;
    int count =0;
    MediaPlayer mediaPlayer;
    Thread recordThread;

    private Button recordButton;
    private Button playButton;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_my);

        currentFileDir = getFilesDir().getAbsolutePath() + "Record.pcm";

        recordButton = (Button)findViewById(R.id.RecordButton);
        recordButton.setOnClickListener(new MyOCL());
        playButton = (Button)findViewById(R.id.PlayButton);
        playButton.setOnClickListener(new MyOCL());

    }

    protected void record(){
        file = new File(currentFileDir);
        BUFFER_SIZE = AudioRecord.getMinBufferSize(SAMPLE_RATE, CONFIG, ENCODING);
        recorder = new AudioRecord(SOURCE, SAMPLE_RATE, CONFIG, ENCODING, BUFFER_SIZE);
        isRecording = true;
        b = new byte[BUFFER_SIZE];

        try{
            FOS = new FileOutputStream(file);
        }
        catch (Exception e){Log.e("Open FOS", "new failed");}

        while (isRecording){
            recorder.read(b, 0, BUFFER_SIZE);
            try{
                FOS.write(b, count * BUFFER_SIZE, BUFFER_SIZE);
                count++;
            }
            catch (Exception e){Log.e("write FOS", "write failed");}
        }

        try {
            FOS.close();
        }
        catch (Exception e){Log.e("close FOS", "close failed");}
    }

    private class MyOCL implements View.OnClickListener{
        @Override
        public void onClick(View view){
            switch(view.getId()){
                case R.id.PlayButton:
                    if(isPlaying == false){
                        playButton.setText("Stop Playing");
                        setPlaying();
                        mediaPlayer.start();
                    }
                    else {
                        playButton.setText("Start Playing");
                        mediaPlayer.stop();
                        mediaPlayer.release();
                        mediaPlayer.reset();
                    }
                    break;
                case R.id.RecordButton:
                    if(isRecording == false) {
                        recordThread = new Thread(new Runnable() {
                            @Override
                            public void run() {
                                record();
                            }
                        });
                        recordThread.start();
                        recordButton.setText("Stop Recording");
                    }
                    else{
                        recordButton.setText("Start recording");
                        isRecording = false;
                    }
                    break;
            }
        }
    }

    protected void setPlaying(){
        try{
            mediaPlayer = new MediaPlayer();
            mediaPlayer.reset();
            mediaPlayer.setDataSource(currentFileDir);
            mediaPlayer.prepare();
            mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
            //mediaPlayer.start();
        }
        catch (Exception e){
            Log.e("Play initialize", "Can't call prepare function" + e.getMessage());
        }
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.my, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();
        if (id == R.id.action_settings) {
            return true;
        }
        return super.onOptionsItemSelected(item);
    }
}

这是我的代码,对我有用:

public class MainActivity extends Activity
{
    AudioRecord record = null;
    AudioTrack track = null;

    boolean isRecording;
    int sampleRate = 44100;

    Button startRecord, stopRecord, playRecord = null;

    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        setVolumeControlStream(AudioManager.MODE_IN_COMMUNICATION);
        startRecord = (Button) findViewById(R.id.start_recording);
        stopRecord = (Button) findViewById(R.id.stop_recording);
        playRecord = (Button) findViewById(R.id.play_recording);
        startRecord.setOnClickListener(new StartRecordListener());
        stopRecord.setOnClickListener(new StopRecordListener());
        playRecord.setOnClickListener(new PlayRecordListener());

        stopRecord.setEnabled(false);
    }

    private void startRecord()
    {
        File recordFile = new File(Environment.getExternalStorageDirectory(), "Record.pcm");
        try
        {
            recordFile.createNewFile();

            OutputStream outputStream = new FileOutputStream(recordFile);
            BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(outputStream);
            DataOutputStream dataOutputStream = new DataOutputStream(bufferedOutputStream);

            int minBufferSize = AudioRecord.getMinBufferSize(sampleRate, AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT);

            short[] audioData = new short[minBufferSize];

            record = new AudioRecord(MediaRecorder.AudioSource.MIC, sampleRate, AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT,
                                     minBufferSize);
            record.startRecording();

            while (isRecording)
            {
                int numberOfShort = record.read(audioData, 0, minBufferSize);
                for (int i = 0; i < numberOfShort; i++)
                {
                    dataOutputStream.writeShort(audioData[i]);
                }
            }
            record.stop();
            dataOutputStream.close();
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }
    }

    public void playRecord()
    {
        File recordFile = new File(Environment.getExternalStorageDirectory(), "Record.pcm");

        int shortSizeInBytes = Short.SIZE / Byte.SIZE;
        int bufferSizeInBytes = (int) (recordFile.length() / shortSizeInBytes);
        short[] audioData = new short[bufferSizeInBytes];
        try
        {
            InputStream inputStream = new FileInputStream(recordFile);
            BufferedInputStream bufferedInputStream = new BufferedInputStream(inputStream);
            DataInputStream dataInputStream = new DataInputStream(bufferedInputStream);

            int i = 0;
            while (dataInputStream.available() > 0)
            {
                audioData[i] = dataInputStream.readShort();
                i++;
            }

            dataInputStream.close();

            track = new AudioTrack(AudioManager.STREAM_MUSIC, sampleRate, AudioFormat.CHANNEL_OUT_MONO, AudioFormat.ENCODING_PCM_16BIT,
                                   bufferSizeInBytes, AudioTrack.MODE_STREAM);

            track.play();
            track.write(audioData, 0, bufferSizeInBytes);
        }
        catch (FileNotFoundException e)
        {
            e.printStackTrace();
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }
    }


    public class StartRecordListener implements View.OnClickListener
    {
        @Override
        public void onClick(View v)
        {
            Thread recordThread = new Thread(new Runnable()
            {
                @Override
                public void run()
                {
                    isRecording = true;
                    MainActivity.this.startRecord();
                }
            });
            recordThread.start();
            startRecord.setEnabled(false);
            stopRecord.setEnabled(true);
        }
    }

    public class StopRecordListener implements View.OnClickListener
    {
        @Override
        public void onClick(View v)
        {
            isRecording = false;
            startRecord.setEnabled(true);
            stopRecord.setEnabled(false);
        }
    }

    public class PlayRecordListener implements View.OnClickListener
    {
        @Override
        public void onClick(View v)
        {
            MainActivity.this.playRecord();
        }
    }
}

XML 布局包含 3 个具有以下 ID 的按钮:start_recording、stop_recording、play_recording

并添加以下权限:

<uses-permission android:name="android.permission.RECORD_AUDIO"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

祝你好运,希望你没问题,我在上面的代码中使用了 3 个按钮。