Android 音频相关
在 Android 中,音频采集常用的配置属性有以下几个:
-
音频源
Audio Source
属性,用于指定采集音频数据的来源。例如:MediaRecorder.AudioSource.MIC
:从麦克风采集音频数据。MediaRecorder.AudioSource.DEFAULT
:使用默认的音频输入进行录制。
-
采样率
Sample Rate
属性,指定录制时的采样率。采样率越高,能够表示的声音的频率就越高,音质也就越好。Android 中支持的采样率有:8000Hz、11025Hz、16000Hz、22050Hz、44100Hz。 -
声道数
Channel Configuration
属性,指定录制时的声道数目。单声道可以满足大部分需求,但某些场景下需要使用立体声或其他声道配置。常见的值有CHANNEL_IN_MONO(单声道)
和CHANNEL_IN_STEREO(立体声)
。 -
编码格式
Audio Format
属性,指定编码时的比特率、编码类型等参数。最常用的是 16 位的 PCM 编码,它可以通过指定字节序为大端或小端来存储数据。 -
缓冲区大小
Buffer Size
属性,定义了一次读取/写入的数据量大小。缓冲区大小会直接影响音频数据的处理效率。
以下是采集 PCM 音频数据并将其保存到文件中的示例代码:
// 设置音频采样率、通道数和编码格式
int sampleRateInHz = 16000; // 采样率为 16kHz
int channelConfig = AudioFormat.CHANNEL_IN_MONO; // 单声道
int audioFormat = AudioFormat.ENCODING_PCM_16BIT; // 采样位深度为 16 bit
// 计算缓存区大小
int bufferSizeInBytes = AudioRecord.getMinBufferSize(sampleRateInHz, channelConfig, audioFormat);
// 创建 AudioRecord 对象
AudioRecord audioRecord = new AudioRecord(MediaRecorder.AudioSource.MIC, sampleRateInHz, channelConfig, audioFormat, bufferSizeInBytes);
// 开始录制音频
audioRecord.startRecording();
// 创建一个字节流用于保存音频数据
String filePath = "/sdcard/test.pcm"
FileOutputStream fos = new FileOutputStream(filePath);
byte[] buffer = new byte[bufferSizeInBytes];
while (true) {
int readSize = audioRecord.read(buffer, 0, bufferSizeInBytes);
fos.write(buffer, 0, readSize);
}
以上代码通过 AudioRecord
类实现了音频数据的采集,并将采集到的 PCM 音频数据写入到文件中。
在 Android 中,音频采集常用的配置属性主要包括以下几项:
- 音频来源(Audio Source):需要指定音频来源,可以是麦克风、电话等。不同的来源有不同的数字表示,例如
MediaRecorder.AudioSource.MIC
表示麦克风。 - 采样率(Sample Rate):指每秒钟采集多少个样本点,单位为 Hz。一般情况下,采样率越高,音频质量越好,但也会占用更多的存储空间和带宽。在 Android 中,常用的采样率有 8000Hz、11025Hz、22050Hz、44100Hz。
- 声道数(Channel Config):指采集的音频是单声道还是立体声。在 Android 中,常用的声道数有 CHANNEL_IN_MONO(单声道)和 CHANNEL_IN_STEREO(立体声)。
- 位深度(Audio Format):指采样点用多少位来表示,一般为 8bit 或 16bit。在 Android 中,常用的位深度为 ENCODING_PCM_16BIT。
音频采集和消费的一个简单实例是录制音频并播放。首先使用 AudioRecord 进行音频采集,然后将采集到的数据进行编码存储(例如 WAV 格式),之后读取已存储的音频数据,并使用 MediaPlayer 播放出来。
其中,可以使用 AudioRecord 的 startRecording() 和 read() 方法进行音频采集,读取到的音频数据就可以进行存储。播放时,则可以使用 MediaPlayer 的 setDataSource() 方法指定要播放的音频文件,并使用 prepare() 和 start() 方法进行播放。需要注意的是,在使用 MediaPlayer 播放时,需要设置正确的音频格式和采样率才能保证播放效果正确。
单声道和双声道音频有什么区别?
在音频采集中,单声道和双声道的区别主要体现在采集到的声音数量和声音方向上。
单声道:只能够采集到来自一个声源的声音。常见于电话录音、语音留言等场景。
双声道:能够采集到多个声源的声音以及声音的方向。通常用于音乐演唱、电影等需要创建立体音效的场景。
在处理音频数据时,双声道相对于单声道会增加了一个声道的数据,因此也需要使用更多的存储空间和处理能力。
一个常见的例子是通过麦克风实时录制用户的声音。可以通过以下代码创建AudioRecord实例并进行采集:
private AudioRecord recorder;
private Thread recordingThread;
// 配置音频参数
int sampleRate = 44100;
int channelConfig = AudioFormat.CHANNEL_IN_MONO;
int audioFormat = AudioFormat.ENCODING_PCM_16BIT;
int bufferSize = AudioRecord.getMinBufferSize(sampleRate, channelConfig, audioFormat);
recorder = new AudioRecord(MediaRecorder.AudioSource.MIC, sampleRate, channelConfig, audioFormat, bufferSize);
// 启动录制线程
recordingThread = new Thread(new Runnable() {
public void run() {
short[] buffer = new short[bufferSize];
while (true) {
// 从音频设备读取音频数据
int read = recorder.read(buffer, 0, bufferSize);
processAudioData(buffer, read);
}
}
});
recordingThread.start();
在执行processAudioData
方法中,我们可以对音频数据进行分析和处理。
channelIndexMask
是用于在 AudioRecord
构造函数中配置音频通道的一个参数。它表示你想要采集哪些声道的数据,以比特掩码的形式表示。
默认情况下,如果不指定 channelIndexMask
参数,构造方法将使用所有可获得的声道。对于双声道输入,则是左右两个声道,对于四声道输入,则是四个声道,以此类推。
如果要只采集单个声道,则可以使用其相应位的掩码,例如,如果要只使用左声道采集,可以设置 channelIndexMask
为二进制字符串 01
,这意味着第一位(从右到左)将被设置为 1,而其他位将被设置为 0。
示例: 如果设备支持4个通道,则以下值是有效的 channelIndexMask:
0b0001
:仅使用通道索引为 0 的通道0b0011
:使用通道索引为0和1的通道(左,右)0b1111
:使用所有四个通道
请注意,channelIndexMask
参数只能由那些 Android 平台版本高于 API 级别 23 的设备使用。更早的平台版本则需要使用其他方式来管理多个通道的输入。
音频链路
Android音频采集流程中涉及的主要模块和传递顺序如下:
- 麦克风/耳麦等音频源 ->
- Audio HAL (Hardware Abstraction Layer)分层,将硬件设备操作抽象为一系列函数接口 ->
- AudioFlinger服务,维护所有音频的全局状态,处理多路音频数据混合、重定向、路由控制等任务 ->
- Audio Policy Service,管理所有音频策略,如声音通道路由、音量调节、AudioSession routing,检查权限等功能 ->
- 应用程序,使用AudioRecord API访问从MIC捕获到的原始音频数据,或使用MediaRecorder API进行音频录制,或使用OpenSL ES在NDK开发中访问底层的音频资源。应用程序可以对音频数据进行处理和缓存。
其中,AudioFlinger和AudioPolicyService都是由system_server启动并运行的系统服务。
这里简单介绍一下各个模块之间的关系:
- 麦克风等音频源通过HAL暴露给上层模块(比如AudioFlinger)。
- AudioFlinger在初始化时,会通过HAL提供的接口获取硬件信息,并创建相应的AudioRecord和AudioTrack对象来进行音频数据的采集和播放。
- AudioFlinger还负责对多路音频进行混音和处理,同时控制音频的路由和音量管理等任务。
- Audio Policy Service则为AudioFlinger提供了统一的音频策略管理,包括声道路由、音量调节、权限控制等功能。
- 应用程序使用AudioRecord接口可以直接访问从MIC中捕获到的原始音频数据,在应用级别进行各种处理,如语音识别、音频编码等等。