录音功能一般使用MediaRecorder来进行,这种录音方式比较简单,设置好声音源、采样率和编码格式等参数即可,最终得到的是编码压缩后的数据。不过由于我们需要对音频原始数据进行处理,例如混音、变声等操作,所以MediaRecorder不能满足我们的要求。这里介绍下另一种录音工具类 AudioRecord。通过它我们可以对原始音频数据进行采集,以便于后续加工。
AudioRecord
AudioRecord的初始化:
1 2 3 4 5 6 7
| int sampleRate = 44100; //音频采样率 int channelConfig = AudioFormat.CHANNEL_IN_STEREO; //音频录制通道,默认为立体声 int audioFormat = AudioFormat.ENCODING_PCM_16BIT; //音频录制格式,默认为PCM16Bit int bufferSize = AudioRecord.getMinBufferSize(sampleRate, channelConfig, audioFormat);//设置bufferSize为AudioRecord所需最小bufferSize的两倍 AudioRecord mRecorder = new AudioRecord(MediaRecorder.AudioSource.MIC, sampleRate, channelConfig, audioFormat, bufferSize);//初始化录音器 mRecorder.startRecording();
|
AudioRecord构造参数:
audioSource 音源,MediaRecorder.AudioSource.MIC 代表音源是麦克风
sampleRate 采样率,由于声音是一种连续的模拟信号,我们要对其进行取样,从而将模拟信号转为离散的数字信号加以利用。采样率则决定了每秒对模拟信号进行采样的次数,这里采样率为44100,也就是通常所说的44.1khz的采样率
channelConfig 音频通道的设置,通常设置为立体声
audioFormat 音频格式,这里设置为16位PCM,也就是每次采样数据为一个short
bufferSize 每次读取数据的最小size,小于这个会导致单次读取的数据不完整
输出PCM文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| //生成PCM文件 file = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/demo.pcm"); //如果存在,就先删除再创建 if (file.exists()) file.delete(); try { file.createNewFile(); } catch (IOException e) { throw new IllegalStateException("未能创建" + file.toString()); } try { //输出流 OutputStream os = new FileOutputStream(file); BufferedOutputStream bos = new BufferedOutputStream(os); DataOutputStream dos = new DataOutputStream(bos); //设置bufferSize为AudioRecord所需小bufferSize的两倍 int bufferSize = AudioRecord.getMinBufferSize(sampleRate, channelConfig, audioFormat) * 2; short[] buffer = new short[bufferSize]; isRecording = true; while (isRecording) { int bufferReadResult = mRecorder.read(buffer, 0, bufferSize); for (int i = 0; i < bufferReadResult; i++) { dos.writeShort(buffer[i]); } } mRecorder.stop(); dos.close(); } catch (Exception e) { e.printStackTrace(); }
|
上面的代码将收集到的PCM数据保存到demo.pcm文件,因为是16位PCM格式,所以每个音元均为short型,这点很重要,后面不管是播放还是混音,都要以转换成short型再进行操作。
AudioTrack
一般播放音频我们使用MediaPlayer即可,MediaPlayer支持的音频格式较多,如mp3,aac,wma等,而且调用方式也比较简单,其原理是将输入的音频数据先进行解码,最终MediaPlayer的底层还是要用到AudioTrack来播放解码后的PCM数据,上面我们已经采集到了PCM数据,这里将AudioRecord采集到的数据进行播放。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| if (file == null) { file = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/demo.pcm"); } //读取文件 int musicLength = (int) (file.length() / 2); short[] music = new short[musicLength]; try { AudioTrack audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, sampleRate, channelConfig, AudioFormat.ENCODING_PCM_16BIT, (int) file.length(), AudioTrack.MODE_STREAM); audioTrack.play(); InputStream is = new FileInputStream(file); BufferedInputStream bis = new BufferedInputStream(is); DataInputStream dis = new DataInputStream(bis); int i = 0; while (dis.available() > 0) { music[i] = dis.readShort(); i++; } audioTrack.write(music, 0, musicLength);//写入数据 audioTrack.stop(); dis.close(); } catch (Exception e) { }
|
AudioTrack有两种播放方式,static和streaming,上面的播放方式为streaming,需要先启动AudioTrack,然后可以将音频数据分段写入(上面的代码中并没有进行分段,可以从后半段数据开始写入,则只播放后半段音频),这里采用了16位PCM的格式,所以每次写入的数据都要为short型的整数倍。而static模式则会一次写入所有的音频数据,然后再启动AudioTrack,这种方式适用于音频数据量较小的情况。
总结
以上为PCM音频数据的采集和播放,这只是最初的一步,有了PCM数据我们就可以进行混音、变音等操作,最终还要进行编码后才能与视频流进行混合。Android音频系统博大精深,之前看到一篇文章,对整个音频系统分析的很透彻,令人叹为观止,有兴趣的同学都可以学习下。