Android Studio:AudioTrack高频播放生成音频崩溃问题求助
解决AudioTrack高频播放崩溃与二次播放无响应问题
看起来你遇到的两个问题都和AudioTrack资源管理以及MODE_STATIC模式的使用逻辑直接相关,咱们一步步拆解解决:
问题1:高频播放(15Hz+)崩溃的核心原因
每次调用playGeneratedSound()都新建AudioTrack对象,但完全没有释放资源。Android系统的音频硬件资源是有限的,高频创建未回收的AudioTrack会快速耗尽系统资源,触发内存溢出(OOM)或者系统强制终止应用。
问题2:单次生成音频后二次播放无响应的原因
在MODE_STATIC模式下,AudioTrack播放结束后会停在缓冲区末尾,状态变为PLAYSTATE_STOPPED,如果不重置播放位置,直接再次调用play()不会有任何反应。另外你的generateSound()方法还存在逻辑漏洞:参数传入的duration重新计算后,循环却使用this.buffer.length,如果传入的duration和构造函数初始化的不一致,会导致数据写入不完整或数组越界。
修正方案与代码示例
1. 核心优化点
- 复用
AudioTrack对象,避免频繁创建销毁导致的资源泄漏 - 修正
generateSound的逻辑错误,确保音频数据长度与buffer匹配 - 正确处理
MODE_STATIC模式的二次播放流程,重置播放头位置
2. 修正后的完整代码
import android.media.AudioFormat; import android.media.AudioManager; import android.media.AudioTrack; public class SoundGenerator { private float duration; private short[] buffer; // 将AudioTrack设为类属性,实现资源复用 private AudioTrack generatedSound; public SoundGenerator() { } public SoundGenerator(float duration) { this.duration = duration; // 计算buffer长度:采样率44100 * 位深2字节(16bit) * 时长(秒) int bufferSize = (int) (duration * 44100 * 2); buffer = new short[bufferSize / 2]; // short类型占2字节,所以数组长度为bufferSize/2 // 提前初始化AudioTrack资源 initAudioTrack(bufferSize); } private void initAudioTrack(int bufferSize) { if (generatedSound != null) { // 先释放旧资源再创建新的 releaseAudioTrack(); } generatedSound = new AudioTrack( AudioManager.STREAM_MUSIC, 44100, AudioFormat.CHANNEL_OUT_MONO, AudioFormat.ENCODING_PCM_16BIT, bufferSize, AudioTrack.MODE_STATIC ); } public void generateSound(double frequency) { int sampleCount = buffer.length; for (int i = 0; i < sampleCount; i++) { // 简化正弦波计算公式,避免浮点运算误差 double sineValue = Math.sin(2.0 * Math.PI * i * frequency / 44100); buffer[i] = (short) (sineValue * Short.MAX_VALUE); } // 重新写入更新后的音频数据到AudioTrack if (generatedSound != null) { generatedSound.write(buffer, 0, sampleCount); } } public void playGeneratedSound(float volume) { if (generatedSound == null) { return; } // 停止当前正在播放的音频(如果有的话) if (generatedSound.getPlayState() == AudioTrack.PLAYSTATE_PLAYING) { generatedSound.stop(); } // 重置播放头到缓冲区起始位置,确保二次播放从开头开始 generatedSound.setPlaybackHeadPosition(0); // 设置播放音量 generatedSound.setStereoVolume(volume, volume); // 启动播放 generatedSound.play(); } // 提供资源释放方法,务必在页面销毁时调用,避免内存泄漏 public void releaseAudioTrack() { if (generatedSound != null) { if (generatedSound.getPlayState() == AudioTrack.PLAYSTATE_PLAYING) { generatedSound.stop(); } generatedSound.release(); generatedSound = null; } } }
3. 额外注意事项
- 调用完
SoundGenerator后,一定要在合适的生命周期(比如Activity的onDestroy())调用releaseAudioTrack(),彻底释放音频资源 - 如果需要动态修改音频时长,不要直接修改
duration,而是新增类似updateDuration(float newDuration)的方法,重新初始化buffer和AudioTrack - 高频播放时,确保
playGeneratedSound()的调用间隔不要小于音频实际时长,避免音频叠加或播放混乱
内容的提问来源于stack exchange,提问作者MasterGrey
相关产品推荐
相关产品推荐

