在学习Android Audio模块之前,我们先了解整体的Audio模块框架和一些涉及到的基础属性概念。如下图是Android Audio模块整体框架图

以播放为例,使用AudioTrack播放会通过JNI在C++层也创建相应的AudioTrack类,这个相当于客户端,会通过binder最终在AudioFlinger中创建相应的Track类,播放的音频数据通过共享环形缓存区进行传递给AudioFlinger,AudioFlinger中创建了回放线程如MixerThread将多个track混音后传递给Hal层,hal使用tinyalsa库发送给内核驱动进行播放。这个链路中有三个进程,一个是App自己播放的进程,如在App创建AudioTrack播放PCM数据,AudioTrack 通过JNI创建对应的C++层AudioTrack.cpp 然后就是AudioFlinger 和AudioPolicy所在的进程即audio_server进程。audioFlinger发送音频数据给Hal,Hal层一般在高版本也是单独的进程。
java
import android.media.AudioAttributes;
import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioTrack;
public class AudioTrackPlayer {
private static final int SAMPLE_RATE = 44100; // 采样率
private AudioTrack mAudioTrack;
private boolean isPlaying = false;
public void startPlay() {
// 1. 设置音频参数
int channelConfig = AudioFormat.CHANNEL_OUT_STEREO; // 双声道
int audioFormat = AudioFormat.ENCODING_PCM_16BIT; // 16位PCM
// 2. 计算系统要求的最小缓冲区大小
int minBufferSize = AudioTrack.getMinBufferSize(SAMPLE_RATE, channelConfig, audioFormat);
// 3. 使用 Builder 模式构建实例
mAudioTrack = new AudioTrack.Builder()
.setAudioAttributes(new AudioAttributes.Builder()
.setUsage(AudioAttributes.USAGE_MEDIA)
.setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
.build())
.setAudioFormat(new AudioFormat.Builder()
.setEncoding(audioFormat)
.setSampleRate(SAMPLE_RATE)
.setChannelMask(channelConfig)
.build())
.setBufferSizeInBytes(minBufferSize)
// 设置为流模式 (MODE_STREAM)
.setTransferMode(AudioTrack.MODE_STREAM)
.build();
// 4. 开始播放状态(此时还没数据,是在等待 write)
mAudioTrack.play();
isPlaying = true;
// 5. 在子线程中不断写入数据
new Thread(() -> {
// 生成一段简单的 440Hz 正弦波数据
byte[] pcmData = generateSineWaveData(SAMPLE_RATE, 5); // 5秒长
int offset = 0;
while (isPlaying && offset < pcmData.length) {
// 将数据写入 AudioTrack 的缓冲区
int written = mAudioTrack.write(pcmData, offset, Math.min(minBufferSize, pcmData.length - offset));
if (written > 0) {
offset += written;
} else {
break; // 写入出错
}
}
stopPlay();
}).start();
}
public void stopPlay() {
isPlaying = false;
if (mAudioTrack != null) {
mAudioTrack.stop();
mAudioTrack.release();
mAudioTrack = null;
}
}
/**
* 工具方法:生成一段正弦波 PCM 数据
*/
private byte[] generateSineWaveData(int sampleRate, int durationSeconds) {
int waveCount = sampleRate * durationSeconds;
byte[] data = new byte[waveCount * 2 * 2]; // 16bit, 双声道
double frequency = 440.0; // A4 键频率
for (int i = 0; i < waveCount; i++) {
// 生成正弦波采样点
short sample = (short) (Math.sin(2 * Math.PI * i / (sampleRate / frequency)) * 0x7FFF);
// 左声道
data[i * 4] = (byte) (sample & 0xff);
data[i * 4 + 1] = (byte) ((sample >> 8) & 0xff);
// 右声道
data[i * 4 + 2] = (byte) (sample & 0xff);
data[i * 4 + 3] = (byte) ((sample >> 8) & 0xff);
}
return data;
}
}
在上面播放demo中涉及2个重要的类
AudioFormat:描述采样率 采样格式 采样率
AudioAttributes:描述音频流信息,AudioFlinger和AudioPolicyService通过这个来选择哪个策略,选择哪个输出设备在哪个回放线程上播放,很重要。其中有几个属性
USAGE 音频流用途
ContentType 音频流内容
StreamType :使用哪个音频流如MUSIC,这个是兼容以前的
上面三个参数影响了AudioPolicyService使用哪个策略
mFlags 标志位如FLAG_HW_AV_SYNC FLAG_LOW_LATENCY 会影响选择使用哪个AudioFlinger使用哪个回放线程OutputThread
其他AudioFlinger AudioPolicyService中的概念参考https://blog.csdn.net/weixin_43013761/article/details/89418633