Android 音频相关

发布时间 2023-03-22 21:13:22作者: 懒懒初阳

在 Android 中,音频采集常用的配置属性有以下几个:

  1. 音频源 Audio Source 属性,用于指定采集音频数据的来源。例如:

    • MediaRecorder.AudioSource.MIC:从麦克风采集音频数据。
    • MediaRecorder.AudioSource.DEFAULT:使用默认的音频输入进行录制。
  2. 采样率 Sample Rate 属性,指定录制时的采样率。采样率越高,能够表示的声音的频率就越高,音质也就越好。Android 中支持的采样率有:8000Hz、11025Hz、16000Hz、22050Hz、44100Hz。

  3. 声道数 Channel Configuration 属性,指定录制时的声道数目。单声道可以满足大部分需求,但某些场景下需要使用立体声或其他声道配置。常见的值有 CHANNEL_IN_MONO(单声道)CHANNEL_IN_STEREO(立体声)

  4. 编码格式 Audio Format 属性,指定编码时的比特率、编码类型等参数。最常用的是 16 位的 PCM 编码,它可以通过指定字节序为大端或小端来存储数据。

  5. 缓冲区大小 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音频采集流程中涉及的主要模块和传递顺序如下:

  1. 麦克风/耳麦等音频源 ->
  2. Audio HAL (Hardware Abstraction Layer)分层,将硬件设备操作抽象为一系列函数接口 ->
  3. AudioFlinger服务,维护所有音频的全局状态,处理多路音频数据混合、重定向、路由控制等任务 ->
  4. Audio Policy Service,管理所有音频策略,如声音通道路由、音量调节、AudioSession routing,检查权限等功能 ->
  5. 应用程序,使用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中捕获到的原始音频数据,在应用级别进行各种处理,如语音识别、音频编码等等。