跳到主要内容

音频处理

问题

Android 音频 API 有哪些?如何实现音频录制和播放?

答案

音频 API 层级

API层级延迟适用场景
MediaPlayer高层简单音频/视频播放
SoundPool高层短音效(游戏音效、提示音)
AudioTrack底层PCM 数据播放、实时音频
AudioRecord底层PCM 录音
Oboe (C++)底层最低实时音频(乐器、音效处理)

AudioTrack 播放 PCM

// PCM 播放
val sampleRate = 44100
val bufferSize = AudioTrack.getMinBufferSize(
sampleRate,
AudioFormat.CHANNEL_OUT_STEREO,
AudioFormat.ENCODING_PCM_16BIT
)

val audioTrack = AudioTrack.Builder()
.setAudioAttributes(AudioAttributes.Builder()
.setUsage(AudioAttributes.USAGE_MEDIA)
.setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
.build())
.setAudioFormat(AudioFormat.Builder()
.setSampleRate(sampleRate)
.setChannelMask(AudioFormat.CHANNEL_OUT_STEREO)
.setEncoding(AudioFormat.ENCODING_PCM_16BIT)
.build())
.setBufferSizeInBytes(bufferSize)
.setTransferMode(AudioTrack.MODE_STREAM)
.build()

audioTrack.play()

// 在子线程中持续写入 PCM 数据
thread {
val buffer = ByteArray(bufferSize)
while (isPlaying) {
val bytesRead = inputStream.read(buffer)
if (bytesRead > 0) {
audioTrack.write(buffer, 0, bytesRead)
}
}
}

AudioRecord 录音

val sampleRate = 44100
val bufferSize = AudioRecord.getMinBufferSize(
sampleRate,
AudioFormat.CHANNEL_IN_MONO,
AudioFormat.ENCODING_PCM_16BIT
)

val audioRecord = AudioRecord(
MediaRecorder.AudioSource.MIC,
sampleRate,
AudioFormat.CHANNEL_IN_MONO,
AudioFormat.ENCODING_PCM_16BIT,
bufferSize
)

audioRecord.startRecording()

thread {
val buffer = ByteArray(bufferSize)
while (isRecording) {
val bytesRead = audioRecord.read(buffer, 0, bufferSize)
if (bytesRead > 0) {
// 处理 PCM 数据:保存、编码、发送
outputStream.write(buffer, 0, bytesRead)
}
}
}

音频焦点

// 请求音频焦点(播放前必须)
val audioManager = getSystemService(Context.AUDIO_SERVICE) as AudioManager
val focusRequest = AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN)
.setAudioAttributes(AudioAttributes.Builder()
.setUsage(AudioAttributes.USAGE_MEDIA)
.build())
.setOnAudioFocusChangeListener { focusChange ->
when (focusChange) {
AudioManager.AUDIOFOCUS_LOSS -> {
// 永久失去焦点:暂停播放
player.pause()
}
AudioManager.AUDIOFOCUS_LOSS_TRANSIENT -> {
// 暂时失去焦点:暂停
player.pause()
}
AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK -> {
// 可降低音量继续播放
player.setVolume(0.3f)
}
AudioManager.AUDIOFOCUS_GAIN -> {
// 恢复焦点:恢复播放和音量
player.setVolume(1.0f)
player.play()
}
}
}
.build()

audioManager.requestAudioFocus(focusRequest)

常见面试问题

Q1: PCM、WAV、AAC、MP3 的区别?

答案

格式类型压缩说明
PCM原始数据未编码的音频采样数据
WAV容器格式PCM + 文件头(采样率、位深等)
AAC编码格式有损比 MP3 更高效,Android 推荐
MP3编码格式有损兼容性最好

PCM 是最原始的音频数据,AudioRecord 录制的就是 PCM,需要编码为 AAC/MP3 才方便存储和传输。

Q2: 什么是音频焦点?为什么要管理它?

答案

音频焦点是 Android 的音频优先级管理机制。多个应用可能同时需要播放音频(音乐 App、导航、电话),音频焦点确保只有一个应用在前台播放,其他应用根据焦点变化暂停或降低音量。不管理音频焦点会导致多个声音同时播放,用户体验差。

相关链接