安卓音视频基础:AudioRecord和AudioTrack的简单使用

在之前的文章安卓实现录音/播放/暂停/继续的功能中介绍了通过MediaRecorder和MediaPlayer实现简单的录音和播放功能,但相比于安卓二次封装后的API,AudioRecord和AudioTrack更接近底层,可通过获取的PCM数据,进行二次的算法处理,实现更加接近需求的声音。

1. AudioRecord

AndioRecord类的主要功能是让各种JAVA应用能够管理音频资源,以便它们通过此类能够录制声音相关的硬件所收集的声音。此功能的实现就是通过”pulling”(读取)AudioRecord对象的声音数据来完成的。在录音过程中,应用所需要做的就是通过后面三个类方法中的一个去及时地获取AudioRecord对象的录音数据. AudioRecord类提供的三个获取声音数据的方法分别是read(byte[], int, int), read(short[], int, int), read(ByteBuffer, int). 无论选择使用那一个方法都必须事先设定方便用户的声音数据的存储格式。

AudioRecord的使用比较简单,获取音频缓冲区buffer后创建AudioRecord对象,buffer用来保存新的录像数据,该buffer是通过api获取的与设备硬件、设置的参数等相关,如果过大导致超过整个录像的数据,过小导致构造AudioRecord对象失败。
使用流程:

  1. 获取缓冲buffer,构建AudioRecord对象;
  2. 创建一个文件的输出流,用于存储buffer数据;
  3. 开始录像;
  4. 暂停/停止录音,释放资源。

下面结合代码分析流程

1. 获取缓冲buffer,构建AudioRecord对象对象;

 BufferSize = AudioRecord.getMinBufferSize(SAMPLE_RATE_HERTZ,
                    CHANNEL_CONFIG, AUDIO_FORMAT);
  mAudioRecord = new AudioRecord(MediaRecorder.AudioSource.MIC,
                    SAMPLE_RATE_HERTZ, CHANNEL_CONFIG, AUDIO_FORMAT, BufferSize);

其中构建AudioRecord对象的对象参数意义如下:

  • audioSource:音频的输入源,包括DEFAULT、MIC、VOICE_x和CAMCORDER等
  • sampleRateInHz:音频采样率,是指1s内对音频信号的采样次数,采样率越高,声音的还原度越高,主流的采集卡的采样频率一般共分为22.05KHz、44.1KHz、48KHz三个等级。
  • channelConfig:声道数,包括单声道(CHANNEL_IN_MONO)和双声道(立体声)(CHANNEL_IN_STEREO),其中CHANNEL_IN_MONO一般是可以兼容其他设备能够使用的。
  • audioFormat:采样位数(量化精度),是指声卡处理声音的解析度,该值越大声音的还原越真实,常见的包括8bit、16bit和32bit,通俗理解为每帧采集的声音大小,类似视频的分辨率。
  • bufferSizeInBytes:通过以上三个参数,调用getMinBufferSize获取音频的缓存区数据。

除了上面介绍的几个概念外,还有一个常见的名称:比特率,又称码率,是指每秒传输的数据大小,单位为bps(Bit Per Second),该值越大,说明包括的音视频数据越多,音视频质量越好,基本的计算公式为:

基本的算法是:【码率】(kbps)=【文件大小】(字节)X8/【时间】(秒)× 1000

2. 创建一个文件的输出流,用于存储buffer数据;

FileOutputStream PcmFos = new FileOutputStream(new File(path));

3. 开始录像;

			//开始录制
                mAudioRecord.startRecording();
			//不断读取音频缓冲区的数据
                while (true == isRecord && !isInterrupted()) {
                    int read = mAudioRecord.read(bytes, 0, bytes.length);
              //若读取数据没有出现错误,将数据写入文件
                    if (AudioRecord.ERROR_INVALID_OPERATION != read) {
                        PcmFos.write(bytes, 0, read);
                        PcmFos.flush();
                    }
                }

4. 暂停/停止录音,释放资源

 mAudioRecord.stop();//暂停录制,如果是单独调用该方法,表示暂停录制操作
 mAudioRecord.release();//停止录制
 PcmFos.close();//关流

在执行停止或暂停操作时,可通过getState()获取当前的运行状态。

2. AudioTrack

对于通过AudioRecord获取的音频数据是不经过编解码处理的数据,因此不能被常见的音频播放器播放,可通过AdobeAudition软件播放,同样安卓调用时需要通过AudioTrack播放,常见的MediaPlayer也无法正常播放,下面讲解一下AudioTrack的使用。
与AudioRecord类似,也需要先获取播放缓冲区,然后构建AudioTrack对象,主要流程如下:

  1. 获取缓冲buffer,构建AudioTrack对象;
  2. 读取pcm文件,调用AudioTrack的write开始播放;
  3. 暂停、停止或释放操作
    流程分析如下:

1. 获取缓冲buffer,构建AudioTrack对象;

 BufferSize = AudioTrack.getMinBufferSize(SAMPLE_RATE_HERTZ,
                    AudioFormat.CHANNEL_OUT_STEREO, AUDIO_FORMAT);
 mAudioTrack = new AudioTrack.Builder()
                    .setAudioAttributes(new AudioAttributes.Builder()
                            .setUsage(AudioAttributes.USAGE_ALARM)
                            .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
                            .build())
                    .setAudioFormat(new AudioFormat.Builder()
                            .setEncoding(AUDIO_FORMAT)
                            .setSampleRate(SAMPLE_RATE_HERTZ)
                            .setChannelMask(AudioFormat.CHANNEL_OUT_STEREO)
                            .build())
                    .setBufferSizeInBytes(BufferSize)
                    .setTransferMode(AudioTrack.MODE_STREAM)
                    .build();                    

这里需要注意以下几点:

  • 调用getMinBufferSize时,添加的三个参数要与AudioRecord设置的参数一致,否则无法正常播放;
  • 获取AudioTrack通过Builder的方式,设置Attributes和Format两种属性,其中Format同样需要与AudioRecord的设置一致,也可以直接通过new的方式构建对象;
  • 通过setTransferMode设置播放方式,包括 MODE_STATIC 或者 MODE_STREAM,其中 MODE_STATIC是预先将播放的数据读取到缓冲区buffer中,然后开始播放,因此需要先调用write方法,然后调用play方法,适用于播放铃声等短小的声音,MODE_STREAM是边读边播的方式,也是默认的方式,由于需要边读边播,因此会有一定的延时。

2. 读取pcm文件,调用AudioTrack的write开始播放

	FileInputStream fis = new FileInputStream(autoFile);
    mAudioTrack.play();
    byte[] bytes = new byte[BufferSize];

        while (true == isRecord) {
                int read = fis.read(bytes);
                //若读取有错则跳过
                    if (AudioTrack.ERROR_INVALID_OPERATION == read
                            || AudioTrack.ERROR_BAD_VALUE == read) {
                        continue;
                    }

       if (read != 0 && read != -1) {
              mAudioTrack.write(bytes, 0, BufferSize);
        } else {
                isRecord = false;
        }

获取到音频的pcm文件后,开始根据buffer的大小读取文件数据,写入到AudioTrack进行播放,该过程可通过添加状态变量isRecord 来循环遍历读取播放。

3. 暂停、停止或释放操作

mAudioTrack.pause();//暂停
mAudioTrack.stop();//停止
mAudioTrack.release();//释放资源
fis.close();//关流
//状态获取
int state = mAudioTrack.getState();

3. PCM转WAV

PCM(Pulse Code Modulation—-脉码调制录音)。所谓PCM录音就是将声音等模拟信号变成符号化的脉冲列,再予以记录。PCM信号是由[1]、[0]等符号构成的数字信号,而未经过任何编码和压缩处理。与模拟信号比,它不易受传送系统的杂波及失真的影响。动态范围宽,可得到音质相当好的影响效果。也就是说,PCM就是没有压缩的编码方式,PCM文件就是采用PCM这种没有压缩的编码方式编码的音频数据文件。
WAV为微软公司(Microsoft)开发的一种声音文件格式,它符合RIFF(Resource Interchange File Format)文件规范,用于保存Windows平台的音频信息资源,被Windows平台及其应用程序所广泛支持,该格式也支持MSADPCM,CCITT A LAW等多种压缩运算法,支持多种音频数字,取样频率和声道,标准格式化的WAV文件和CD格式一样,也是44.1K的取样频率,16位量化数字,因此在声音文件质量和CD相差无几!

PCM是一种直接记录数字信号(0或1)的无损压缩方式,而WAV是通过在PCM的基础上增加其特有的头文件形成的一种音频格式。其添加方法可参考河北-宝哥

4. 常见的录音和播放比较

API 优点 缺点
AudioRecord 获取最底层的音频数据,使用更加灵活,可针对获取的音频数据进行处理,例如压缩、网传或算法处理 常见的播放器无法正常播放,数据量较大
MediaRecorder android在AudioRecord基础上二次封装的API,便于应用层的开发,使用简单方便,适用于常见的音频播放器 无法实施音频处理
AudioTrack 可播放延迟要求低,无须解码的pcm数据 无法播放需要解码的音频文件
MediaPlayer 可播放需要解码的常见音频文件,例如MP3、AAC和WAV等数据 资源占用较高,需要解码处理,延时较高

本文涉及的demo链接

参考链接:
1、https://www.jianshu.com/p/1f78c4211ab7?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation
2、https://blog.csdn.net/haovip123/article/details/52356024

猜你喜欢

转载自blog.csdn.net/xk7298/article/details/106980207