Android 音频播放的多种方式详解
1. 按抽象层次分类
1.1 高层API(最简单)
MediaPlayer - 全功能媒体播放器
java
// 1. 创建MediaPlayer
MediaPlayer mediaPlayer = new MediaPlayer();
// 2. 设置数据源
mediaPlayer.setDataSource(context, uri);
// 或
mediaPlayer.setDataSource(filePath);
// 3. 准备播放
mediaPlayer.prepareAsync(); // 异步准备
// mediaPlayer.prepare(); // 同步准备
// 4. 设置监听器
mediaPlayer.setOnPreparedListener(mp -> {
mp.start(); // 开始播放
});
mediaPlayer.setOnCompletionListener(mp -> {
mp.release(); // 播放完成释放资源
});
// 5. 控制方法
mediaPlayer.start(); // 开始/恢复
mediaPlayer.pause(); // 暂停
mediaPlayer.stop(); // 停止
mediaPlayer.seekTo(ms); // 跳转到指定位置
mediaPlayer.reset(); // 重置
特点:
- 支持多种格式(MP3, AAC, WAV, MP4, 3GP等)
- 自动处理音频焦点
- 支持后台播放
- 网络流媒体支持
- 音量控制、循环播放
SoundPool - 短音频效果播放
java
// 1. 创建SoundPool
SoundPool soundPool = new SoundPool.Builder()
.setMaxStreams(10) // 最大同时播放数
.setAudioAttributes(new AudioAttributes.Builder()
.setUsage(AudioAttributes.USAGE_GAME)
.setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
.build())
.build();
// 2. 加载音频
int soundId = soundPool.load(context, R.raw.beep, 1);
// 3. 播放音频
soundPool.play(soundId, // soundId
1.0f, 1.0f, // 左右声道音量
1, // 优先级
0, // 循环次数(0=不循环)
1.0f); // 播放速度
// 4. 资源管理
soundPool.unload(soundId);
soundPool.release();
特点:
- 低延迟播放短音频
- 支持同时播放多个音频
- 适合游戏音效、提示音
- 音频预加载到内存
JetPlayer - MIDI音乐播放
java
JetPlayer jetPlayer = JetPlayer.getJetPlayer();
jetPlayer.loadJetFile(context, R.raw.music);
jetPlayer.play();
1.2 中层API(更灵活)
AudioTrack - 原始PCM数据播放
java
// 1. 创建AudioTrack
AudioTrack audioTrack = new AudioTrack.Builder()
.setAudioAttributes(new AudioAttributes.Builder()
.setUsage(AudioAttributes.USAGE_MEDIA)
.setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
.build())
.setAudioFormat(new AudioFormat.Builder()
.setEncoding(AudioFormat.ENCODING_PCM_16BIT)
.setSampleRate(44100)
.setChannelMask(AudioFormat.CHANNEL_OUT_STEREO)
.build())
.setBufferSizeInBytes(minBufferSize)
.setPerformanceMode(AudioTrack.PERFORMANCE_MODE_LOW_LATENCY)
.build();
// 2. 播放模式
// MODE_STATIC: 一次性加载所有数据
// MODE_STREAM: 流式播放
// 3. 写入数据
byte[] audioData = getPCMData();
int written = audioTrack.write(audioData, 0, audioData.length,
AudioTrack.WRITE_BLOCKING);
// 4. 控制播放
audioTrack.play();
audioTrack.pause();
audioTrack.stop();
audioTrack.flush();
// 5. 设置监听
audioTrack.setPlaybackPositionUpdateListener(
new AudioTrack.OnPlaybackPositionUpdateListener() {
@Override
public void onMarkerReached(AudioTrack track) {
// 标记点到达
}
@Override
public void onPeriodicNotification(AudioTrack track) {
// 定期通知
}
});
特点:
- 直接播放PCM数据
- 低延迟控制
- 支持多种音频格式
- 适合音频处理、实时合成
ToneGenerator - DTMF/提示音生成
java
ToneGenerator toneGen = new ToneGenerator(
AudioManager.STREAM_MUSIC, // 流类型
ToneGenerator.MAX_VOLUME); // 音量
// 播放DTMF音
toneGen.startTone(ToneGenerator.TONE_DTMF_0);
// 停止
toneGen.stopTone();
1.3 底层API(最灵活,最复杂)
OpenSL ES - 跨平台音频API
c
// C++/NDK中使用
#include <SLES/OpenSLES.h>
#include <SLES/OpenSLES_Android.h>
// 1. 创建引擎
SLresult result;
SLEngineItf engineEngine;
result = slCreateEngine(&engineObject, 0, NULL, 0, NULL, NULL);
result = (*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE);
result = (*engineObject)->GetInterface(engineObject, SL_IID_ENGINE, &engineEngine);
// 2. 创建输出混音器
SLObjectItf outputMixObject;
result = (*engineEngine)->CreateOutputMix(engineEngine, &outputMixObject, 0, NULL, NULL);
result = (*outputMixObject)->Realize(outputMixObject, SL_BOOLEAN_FALSE);
// 3. 创建播放器
SLObjectItf playerObject;
SLPlayItf playerPlay;
SLDataLocator_AndroidSimpleBufferQueue loc_bufq = {
SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, 2};
SLDataFormat_PCM format_pcm = {
SL_DATAFORMAT_PCM, 2, SL_SAMPLINGRATE_44_1,
SL_PCMSAMPLEFORMAT_FIXED_16, SL_PCMSAMPLEFORMAT_FIXED_16,
SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT, SL_BYTEORDER_LITTLEENDIAN};
SLDataSource audioSrc = {&loc_bufq, &format_pcm};
SLDataLocator_OutputMix loc_outmix = {SL_DATALOCATOR_OUTPUTMIX, outputMixObject};
SLDataSink audioSnk = {&loc_outmix, NULL};
const SLInterfaceID ids[1] = {SL_IID_BUFFERQUEUE};
const SLboolean req[1] = {SL_BOOLEAN_TRUE};
result = (*engineEngine)->CreateAudioPlayer(engineEngine, &playerObject,
&audioSrc, &audioSnk, 1, ids, req);
result = (*playerObject)->Realize(playerObject, SL_BOOLEAN_FALSE);
result = (*playerObject)->GetInterface(playerObject, SL_IID_PLAY, &playerPlay);
// 4. 设置缓冲队列回调
SLAndroidSimpleBufferQueueItf playerBufferQueue;
result = (*playerObject)->GetInterface(playerObject, SL_IID_BUFFERQUEUE,
&playerBufferQueue);
result = (*playerBufferQueue)->RegisterCallback(playerBufferQueue,
bqPlayerCallback, NULL);
// 5. 播放
result = (*playerPlay)->SetPlayState(playerPlay, SL_PLAYSTATE_PLAYING);
特点:
- 跨平台标准
- 极低延迟
- 适合专业音频应用
- 需要NDK开发
AAudio - Android 8.0+ 高性能音频
cpp
// C++/NDK中使用
#include <aaudio/AAudio.h>
// 1. 创建流构建器
AAudioStreamBuilder *builder;
aaudio_result_t result = AAudio_createStreamBuilder(&builder);
// 2. 配置流参数
AAudioStreamBuilder_setDirection(builder, AAUDIO_DIRECTION_OUTPUT);
AAudioStreamBuilder_setSampleRate(builder, 48000);
AAudioStreamBuilder_setChannelCount(builder, 2);
AAudioStreamBuilder_setFormat(builder, AAUDIO_FORMAT_PCM_I16);
AAudioStreamBuilder_setSharingMode(builder, AAUDIO_SHARING_MODE_EXCLUSIVE);
AAudioStreamBuilder_setPerformanceMode(builder,
AAUDIO_PERFORMANCE_MODE_LOW_LATENCY);
// 3. 设置数据回调
AAudioStreamBuilder_setDataCallback(builder, dataCallback, nullptr);
AAudioStreamBuilder_setErrorCallback(builder, errorCallback, nullptr);
// 4. 打开流
AAudioStream *stream;
result = AAudioStreamBuilder_openStream(builder, &stream);
// 5. 开始播放
result = AAudioStream_requestStart(stream);
// 6. 数据回调函数
aaudio_data_callback_result_t dataCallback(
AAudioStream *stream,
void *userData,
void *audioData,
int32_t numFrames) {
// 填充音频数据
int16_t *buffer = (int16_t *)audioData;
for (int i = 0; i < numFrames * 2; i++) {
buffer[i] = generateSample(); // 生成音频样本
}
return AAUDIO_CALLBACK_RESULT_CONTINUE;
}
特点:
- Android 8.0+ 原生高性能API
- 比OpenSL ES更简单
- 极低延迟(<10ms)
- 支持独占模式
2. 按使用场景分类
2.1 音乐播放场景
java
// 使用MediaPlayer + Service实现后台播放
public class MusicService extends Service {
private MediaPlayer mediaPlayer;
private AudioManager audioManager;
@Override
public void onCreate() {
mediaPlayer = new MediaPlayer();
// 设置音频属性
mediaPlayer.setAudioAttributes(new AudioAttributes.Builder()
.setUsage(AudioAttributes.USAGE_MEDIA)
.setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
.build());
// 音频焦点监听
audioManager = (AudioManager) getSystemService(AUDIO_SERVICE);
audioManager.requestAudioFocus(focusChangeListener,
AudioManager.STREAM_MUSIC,
AudioManager.AUDIOFOCUS_GAIN);
}
// 实现音频焦点变化监听
private AudioManager.OnAudioFocusChangeListener focusChangeListener =
new AudioManager.OnAudioFocusChangeListener() {
@Override
public void onAudioFocusChange(int focusChange) {
switch (focusChange) {
case AudioManager.AUDIOFOCUS_GAIN:
mediaPlayer.start();
mediaPlayer.setVolume(1.0f, 1.0f);
break;
case AudioManager.AUDIOFOCUS_LOSS:
mediaPlayer.stop();
break;
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
mediaPlayer.pause();
break;
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
mediaPlayer.setVolume(0.1f, 0.1f);
break;
}
}
};
}
2.2 游戏音效场景
java
// SoundPool适合短音效
public class GameAudioManager {
private SoundPool soundPool;
private HashMap<String, Integer> soundMap = new HashMap<>();
public void init(Context context) {
soundPool = new SoundPool.Builder()
.setMaxStreams(20)
.setAudioAttributes(new AudioAttributes.Builder()
.setUsage(AudioAttributes.USAGE_GAME)
.setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
.build())
.build();
// 预加载音效
loadSound(context, R.raw.shoot, "shoot");
loadSound(context, R.raw.explosion, "explosion");
loadSound(context, R.raw.jump, "jump");
}
public void playSound(String soundName) {
Integer soundId = soundMap.get(soundName);
if (soundId != null) {
soundPool.play(soundId, 1.0f, 1.0f, 1, 0, 1.0f);
}
}
}
2.3 实时语音/通话场景
java
// AudioTrack适合实时音频处理
public class VoicePlayer {
private AudioTrack audioTrack;
private Thread playbackThread;
private volatile boolean isPlaying = false;
public void startPlayback() {
int minBufferSize = AudioTrack.getMinBufferSize(
16000, // 采样率
AudioFormat.CHANNEL_OUT_MONO,
AudioFormat.ENCODING_PCM_16BIT);
audioTrack = new AudioTrack.Builder()
.setAudioAttributes(new AudioAttributes.Builder()
.setUsage(AudioAttributes.USAGE_VOICE_COMMUNICATION)
.setContentType(AudioAttributes.CONTENT_TYPE_SPEECH)
.build())
.setAudioFormat(new AudioFormat.Builder()
.setEncoding(AudioFormat.ENCODING_PCM_16BIT)
.setSampleRate(16000)
.setChannelMask(AudioFormat.CHANNEL_OUT_MONO)
.build())
.setBufferSizeInBytes(minBufferSize * 2)
.setPerformanceMode(AudioTrack.PERFORMANCE_MODE_LOW_LATENCY)
.build();
audioTrack.play();
isPlaying = true;
// 启动播放线程
playbackThread = new Thread(() -> {
byte[] buffer = new byte[minBufferSize];
while (isPlaying) {
// 从网络或麦克风获取数据
int bytesRead = getAudioData(buffer);
if (bytesRead > 0) {
audioTrack.write(buffer, 0, bytesRead);
}
}
});
playbackThread.start();
}
}
2.4 音频处理/分析场景
java
// 使用AudioRecord录音 + AudioTrack播放
public class AudioProcessor {
private AudioRecord audioRecord;
private AudioTrack audioTrack;
public void startEcho() {
int sampleRate = 44100;
int channelConfig = AudioFormat.CHANNEL_IN_MONO;
int audioFormat = AudioFormat.ENCODING_PCM_16BIT;
int bufferSize = AudioRecord.getMinBufferSize(sampleRate,
channelConfig, audioFormat);
// 录音
audioRecord = new AudioRecord(
MediaRecorder.AudioSource.MIC,
sampleRate,
channelConfig,
audioFormat,
bufferSize);
// 播放
audioTrack = new AudioTrack.Builder()
.setAudioFormat(new AudioFormat.Builder()
.setEncoding(audioFormat)
.setSampleRate(sampleRate)
.setChannelMask(AudioFormat.CHANNEL_OUT_MONO)
.build())
.setBufferSizeInBytes(bufferSize)
.build();
audioRecord.startRecording();
audioTrack.play();
// 实时处理线程
new Thread(() -> {
byte[] buffer = new byte[bufferSize];
while (true) {
int bytesRead = audioRecord.read(buffer, 0, buffer.length);
// 可以在这里处理音频数据(回声、混响等)
processAudio(buffer, bytesRead);
// 播放处理后的数据
audioTrack.write(buffer, 0, bytesRead);
}
}).start();
}
}
3. 音频焦点管理
3.1 请求音频焦点
java
AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
// 请求焦点
int result = audioManager.requestAudioFocus(
new AudioManager.OnAudioFocusChangeListener() {
@Override
public void onAudioFocusChange(int focusChange) {
// 处理焦点变化
}
},
AudioManager.STREAM_MUSIC, // 流类型
AudioManager.AUDIOFOCUS_GAIN // 焦点类型
);
if (result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
// 获得焦点,可以播放
mediaPlayer.start();
}
3.2 焦点类型
java
// 长期获取焦点(音乐播放)
AudioManager.AUDIOFOCUS_GAIN
// 临时获取焦点(导航提示)
AudioManager.AUDIOFOCUS_GAIN_TRANSIENT
// 临时获取,其他应用降低音量(通知音)
AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK
// 独占临时焦点(语音助手)
AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE
4. 性能优化
4.1 低延迟配置
java
// AudioTrack低延迟配置
AudioTrack audioTrack = new AudioTrack.Builder()
.setAudioAttributes(new AudioAttributes.Builder()
.setUsage(AudioAttributes.USAGE_MEDIA)
.setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
.setFlags(AudioAttributes.FLAG_LOW_LATENCY) // 低延迟标志
.build())
.setAudioFormat(new AudioFormat.Builder()
.setEncoding(AudioFormat.ENCODING_PCM_16BIT)
.setSampleRate(48000)
.setChannelMask(AudioFormat.CHANNEL_OUT_STEREO)
.build())
.setBufferSizeInBytes(AudioTrack.getMinBufferSize(48000,
AudioFormat.CHANNEL_OUT_STEREO,
AudioFormat.ENCODING_PCM_16BIT))
.setPerformanceMode(AudioTrack.PERFORMANCE_MODE_LOW_LATENCY)
.build();
4.2 内存优化
java
// 使用直接缓冲区
ByteBuffer directBuffer = ByteBuffer.allocateDirect(bufferSize);
directBuffer.order(ByteOrder.nativeOrder());
// 写入AudioTrack
int written = audioTrack.write(directBuffer, bufferSize,
AudioTrack.WRITE_BLOCKING);
// 避免频繁创建/销毁对象
private static final AudioTrack[] audioTrackPool = new AudioTrack[5];
private static int poolIndex = 0;
public AudioTrack getAudioTrack() {
if (audioTrackPool[poolIndex] == null) {
audioTrackPool[poolIndex] = createAudioTrack();
}
return audioTrackPool[poolIndex];
}
5. 最佳实践
5.1 错误处理
java
try {
mediaPlayer.setDataSource(path);
mediaPlayer.prepare();
mediaPlayer.start();
} catch (IOException e) {
Log.e("AudioPlayer", "文件错误: " + e.getMessage());
// 尝试其他播放方式
fallbackToAudioTrack();
} catch (IllegalStateException e) {
Log.e("AudioPlayer", "状态错误: " + e.getMessage());
resetMediaPlayer();
} finally {
// 确保资源释放
if (mediaPlayer != null) {
mediaPlayer.release();
}
}
5.2 权限管理
xml
<!-- AndroidManifest.xml -->
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
5.3 后台播放服务
java
// 前台服务,避免被系统杀死
public class MusicService extends Service {
@Override
public void onCreate() {
super.onCreate();
// 创建通知
Notification notification = new Notification.Builder(this, CHANNEL_ID)
.setContentTitle("音乐播放中")
.setContentText("正在播放音乐")
.setSmallIcon(R.drawable.ic_music)
.build();
// 启动前台服务
startForeground(NOTIFICATION_ID, notification);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
// 处理播放控制命令
String action = intent.getAction();
if ("PLAY".equals(action)) {
playMusic();
} else if ("PAUSE".equals(action)) {
pauseMusic();
}
return START_STICKY;
}
}
6. 各方式对比总结
| 方式 | 适用场景 | 延迟 | 复杂度 | 功能 | API Level |
|---|---|---|---|---|---|
| MediaPlayer | 音乐播放、网络流媒体 | 中 | 低 | 高 | 1 |
| SoundPool | 游戏音效、提示音 | 低 | 低 | 中 | 1 |
| AudioTrack | 实时音频、PCM处理 | 低 | 中 | 中 | 3 |
| OpenSL ES | 专业音频、游戏 | 极低 | 高 | 高 | 9+ |
| AAudio | 高性能音频 | 极低 | 中 | 高 | 26+ |
| ToneGenerator | DTMF提示音 | 低 | 低 | 低 | 1 |
7. 选择建议
- 普通音乐播放 → MediaPlayer(功能全,易用)
- 游戏音效 → SoundPool(支持并发,低延迟)
- 语音通话/录音 → AudioTrack(实时控制)
- 专业音频应用 → AAudio/OpenSL ES(高性能)
- 系统提示音 → ToneGenerator/Notification
8. 调试工具
bash
# 查看音频设备
adb shell dumpsys audio
# 查看音频服务状态
adb shell dumpsys media.audio_flinger
adb shell dumpsys media.audio_policy
# 性能分析
adb shell dumpsys media.metrics
# 延迟测试
adb shell am start -a android.media.action.DISPLAY_AUDIO_LATENCY
根据具体需求选择合适的播放方式,平衡性能、功能和开发复杂度。