使用 AudioRecord 录制音频

Posted

技术标签:

【中文标题】使用 AudioRecord 录制音频【英文标题】:Audio recording using AudioRecord 【发布时间】:2015-01-08 18:34:37 【问题描述】:

我决定使用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);
    

【问题讨论】:

您应该提供有关“应用程序无法正常工作”的详细信息 由于某种原因,该文件没有被保存。稍后我会添加一些日志,但问题在于似乎无限的 while(isRecording) 循环。 【参考方案1】:

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

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 个按钮。

【讨论】:

非常感谢!我来看看代码。我看到你使用了短裤并将它们解析为字节......这是为什么呢? 您可以将 record.read() 给出的字节直接存储到您的输出流中。 那么有什么解释为什么当我用 OutputStream(而不是中间的缓冲区)初始化 DataOutputStream 时,音频要快得多? (我认为比现实快 2 倍) 对不起,我不明白你的意思。您可以尝试上面的示例并对其进行测量。 我试过了,效果很好,我只是想知道是什么原因造成的

以上是关于使用 AudioRecord 录制音频的主要内容,如果未能解决你的问题,请参考以下文章

使用 AudioRecord 录制音频

使用 AudioRecord 以 .mp3 格式录制音频

Android 音频录制-AudioRecord

Android:使用 audiorecord 类录制音频播放快进

音频的录制方式-AudioRecord,MediaRecorder的使用及播放

录制音频,然后使用 AudioRecord、AudioTrack.trouble 播放