模拟器中的java Android AudioTrack速度异常
我在Android emulator中遇到了一些与AudioTrack
相关的奇怪行为。然而,我似乎无法确定这是我的一个编码错误,还是模拟器中的一个错误(可能与我在M1 Mac上运行的事实有关)。我确实有一个物理Android设备(它没有遇到这个问题),但它是在旧版本的Android上,所以可以想象,在新版本中,这是一个行为差异,而不是实际的模拟器问题
问题:
有了我提供的代码(这是一个最小的、可复制的样本——真正的应用程序是一个节拍器,它将动态生成的样本数据输入到AudioTrack
)中),我希望每秒播放两次短暂的静态脉冲(例如每分钟120次)。相反,我所经历的是短暂的、有点随机的静电爆发。最终,在开始/停止赛道几次后,爆发以我预期的时间结束。这首有声曲目似乎需要“迎头赶上”,所以一开始播放得太快了
你可以在这里看到这个问题:https://youtu.be/iI4msI5ay60——第一次按下按钮就说明了这个问题。在第二次按下按钮时,几秒钟后计时“固定”。所有随后的按钮按下都将在正确的时间
我注意到,如果每次调用start
时创建一个新的AudioTrack
,这个问题会变得不那么频繁,但不会完全消失
问题:
我是不是在做什么导致这个问题(比如,我可以改成代码来解决它)?这是一个模拟器错误,还是如果我不解决这个问题,我会让人们在他们的设备上体验到同样的行为
代码:
import 安卓.content.Context;
import 安卓.media.AudioFormat;
import 安卓.media.AudioManager;
import 安卓.media.AudioTrack;
import 安卓.os.Bundle;
import 安卓.util.Log;
import 安卓.view.View;
public class MainActivity extends AppCompatActivity {
ExampleAudioManager audioManager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
audioManager = new ExampleAudioManager(this.getApplicationContext());
}
public void buttonPressed(View view) {
if (audioManager.isRunning()) {
audioManager.stop();
} else {
audioManager.start();
}
}
}
class ExampleAudioManager {
private static final int INT16_MAX = Short.MAX_VALUE;
private final AudioTrack audioTrack;
int sampleSizeInFrames = 44100 / 20;
Thread m_audioThread;
private boolean stopFlag;
AudioManager.OnAudioFocusChangeListener focusListener;
Context appContext;
public ExampleAudioManager(Context context) {
this.appContext = context;
int sampleRate = 44100;
audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, sampleRate,
AudioFormat.CHANNEL_OUT_STEREO, AudioFormat.ENCODING_PCM_16BIT,
sampleSizeInFrames * 4, AudioTrack.MODE_STREAM);
}
public boolean isRunning() {
if (m_audioThread == null) return false;
return m_audioThread.isAlive();
}
Runnable m_AudioThreadRunnable = () -> {
Thread.currentThread().setPriority(Thread.MAX_PRIORITY);
play();
};
public void start() {
Log.d("AudioTrackDebug","Start...");
// audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, sampleRate,
// AudioFormat.CHANNEL_OUT_STEREO, AudioFormat.ENCODING_PCM_16BIT,
// sampleSizeInFrames * 4, AudioTrack.MODE_STREAM);
if (focusListener == null) {
focusListener = focusChange -> {
Log.i("audio","Audio focus change");
if (focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT) {
// Pause playback
ExampleAudioManager.this.stop();
} else if (focusChange == AudioManager.AUDIOFOCUS_GAIN) {
// Resume playback
if (!ExampleAudioManager.this.isRunning()) {
ExampleAudioManager.this.start();
}
} else if (focusChange == AudioManager.AUDIOFOCUS_LOSS) {
ExampleAudioManager.this.stop();
// Stop playback
}
};
}
AudioManager am = (AudioManager) appContext.getSystemService(Context.AUDIO_SERVICE);
int result = am.requestAudioFocus(focusListener, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);
if (result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
stopFlag = false;
m_audioThread = new Thread(m_AudioThreadRunnable);
m_audioThread.start();
} else {
Log.e("AudioFocus","Focus not granted: " + result);
}
}
public void stop() {
AudioManager am = (AudioManager) appContext.getSystemService(Context.AUDIO_SERVICE);
am.abandonAudioFocus(focusListener);
stopFlag = true;
audioTrack.stop();
}
public void cleanUp() {
audioTrack.release();
}
private void play() {
audioTrack.setPlaybackHeadPosition(0);
audioTrack.play();
int sampleSizeInBytes = sampleSizeInFrames * 4;
int sampleSizeInShorts = sampleSizeInBytes / 2;
short[] frameBuffer = new short[sampleSizeInBytes];
long currentTimeInFrames;
int inNumberFrames = sampleSizeInFrames;
currentTimeInFrames = -inNumberFrames;
while (!stopFlag) {
currentTimeInFrames += inNumberFrames;
for (int i = 0; i < sampleSizeInShorts; i++) {
if ((currentTimeInFrames + i) % 22050 < 2000) {
frameBuffer[i] = (short) (Math.random() * INT16_MAX);
} else {
frameBuffer[i] = 0;
}
}
audioTrack.write(frameBuffer, 0, sampleSizeInShorts);
}
stopFlag = false;
}
}
共 (0) 个答案