【发布时间】:2010-07-22 03:30:21
【问题描述】:
好的,我有一个频率发生器,它使用 AudioTrack 将 PCM 数据发送到硬件。这是我使用的代码:
private class playSoundTask extends AsyncTask<Void, Void, Void> {
float frequency;
float increment;
float angle = 0;
short samples[] = new short[1024];
@Override
protected void onPreExecute() {
int minSize = AudioTrack.getMinBufferSize( 44100, AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT );
track = new AudioTrack( AudioManager.STREAM_MUSIC, 44100,
AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT,
minSize, AudioTrack.MODE_STREAM);
track.play();
}
@Override
protected Void doInBackground(Void... params) {
while( Main.this.isPlaying)
{
for( int i = 0; i < samples.length; i++ )
{
frequency = (float)Main.this.slider.getProgress();
increment = (float)(2*Math.PI) * frequency / 44100;
samples[i] = (short)((float)Math.sin( angle )*Short.MAX_VALUE);
angle += increment;
}
track.write(samples, 0, samples.length);
}
return null;
}
}
频率与滑动条相关联,并且在样本生成循环中报告了正确的值。当我启动应用程序时,一切都很好。当您沿着滑动条拖动手指时,您会听到清脆的声音。但是在玩了大约 10 秒后,音频开始变得跳跃。它不是平滑扫描,而是交错的,并且仅在每 1000 Hz 左右改变音调。关于可能导致此问题的任何想法?
以下是所有代码,以防问题出在其他地方:
public class Main extends Activity implements OnClickListener, OnSeekBarChangeListener {
AudioTrack track;
SeekBar slider;
ImageButton playButton;
TextView display;
boolean isPlaying=false;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
display = (TextView) findViewById(R.id.display);
display.setText("5000 Hz");
slider = (SeekBar) findViewById(R.id.slider);
slider.setMax(20000);
slider.setProgress(5000);
slider.setOnSeekBarChangeListener(this);
playButton = (ImageButton) findViewById(R.id.play);
playButton.setOnClickListener(this);
}
private class playSoundTask extends AsyncTask<Void, Void, Void> {
float frequency;
float increment;
float angle = 0;
short samples[] = new short[1024];
@Override
protected void onPreExecute() {
int minSize = AudioTrack.getMinBufferSize( 44100, AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT );
track = new AudioTrack( AudioManager.STREAM_MUSIC, 44100,
AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT,
minSize, AudioTrack.MODE_STREAM);
track.play();
}
@Override
protected Void doInBackground(Void... params) {
while( Main.this.isPlaying)
{
for( int i = 0; i < samples.length; i++ )
{
frequency = (float)Main.this.slider.getProgress();
increment = (float)(2*Math.PI) * frequency / 44100;
samples[i] = (short)((float)Math.sin( angle )*Short.MAX_VALUE);
angle += increment;
}
track.write(samples, 0, samples.length);
}
return null;
}
}
@Override
public void onProgressChanged(SeekBar seekBar, int progress,
boolean fromUser) {
display.setText(""+progress+" Hz");
}
public void onClick(View v) {
if (isPlaying) {
stop();
} else {
start();
}
}
public void stop() {
isPlaying=false;
playButton.setImageResource(R.drawable.play);
}
public void start() {
isPlaying=true;
playButton.setImageResource(R.drawable.stop);
new playSoundTask().execute();
}
@Override
protected void onResume() {
super.onResume();
}
@Override
protected void onStop() {
super.onStop();
//Store state
stop();
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
// TODO Auto-generated method stub
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
// TODO Auto-generated method stub
}
}
【问题讨论】:
-
不直接回答您的问题,但作为旁注,请注意进度条和流媒体存在一个已知问题:code.google.com/p/android/issues/detail?id=4124 尽管您的问题不是进度条本身而是音频流。因此,这不是解决您的问题的方法,但由于您使用的是音频流,因此您应该知道其中存在一个或多个未解决的错误。
-
我也有同样的问题。缓冲区越大,跳跃开始的越晚。在日志中,我看到了很多非常长的 GC(GC 在 4200 毫秒内清理了 180 个对象)。我没有做任何分配。在 DDMS 分配跟踪器中,AudioTrack 本身似乎正在执行分配。不确定 GC 是否与跳跃有关。你解决了吗?
-
你清理过你的“音轨”吗?这可能是与内存相关的问题
-
请分享 onPostExecute 方法