【问题标题】:Playing repeated AudioTrack in android activity在android活动中播放重复的AudioTrack
【发布时间】:2014-01-20 07:05:06
【问题描述】:

我想播放以指定速率重复的音调脉冲,例如每秒 3 次。它工作了大约 20 次,然后崩溃如下。

void playSound() {
    final AudioTrack audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, sampleRate, AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT, generatedSnd.length, AudioTrack.MODE_STATIC);
    audioTrack.write(generatedSnd, 0, generatedSnd.length);
    audioTrack.play();
}

在异步任务中,我运行一个连续循环来检查时间并在需要时调用 playSound。它工作了几秒钟,然后得到这个错误,

01-02 18:24:45.035: E/AndroidRuntime(6599): Caused by: java.lang.IllegalStateException: play() called on uninitialized AudioTrack.

即使每次都初始化轨道。

任何迹象表明我做错了什么?还是可以做得更好?

代码如下:

public class DisplayBowieActivity extends Activity {

private final int duration = 200; // seconds
private final int sampleRate = 8000;
private final int numSamples = duration * sampleRate / 1000;
private double sample[];// =new double[numSamples];
private final double freqOfTone = 1440; // hz
private int pulseLength;
private byte generatedSnd[];// = new byte[2 * numSamples];
private int period = 4; // hz
private AudioTrack audioTrack;
Handler handler = new Handler();

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_display_bowie);

    Intent intent = getIntent();
    String smessage = intent.getStringExtra(MainActivity.SOUND_MESSAGE);
    period = Integer.parseInt(smessage);
    pulseLength = duration * sampleRate / 1000;
    System.out.print("+++ Period " + period);
    System.out.print("+++ Pulse " + pulseLength);

    genTone();

    View view = this.getWindow().getDecorView();
    view.setBackgroundColor(Color.parseColor("#8E8E38"));

}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.display_bowie, menu);
    return true;
}

@Override
protected void onResume() {
    super.onResume();

    new SoundGen().execute(period);

}

private class SoundGen extends AsyncTask<Integer, Void, Void> {
    @Override
    protected Void doInBackground(Integer... hz) {
        long mils = (int) (1000.0 / hz[0]);
        long start = System.currentTimeMillis();
        long next = start + mils;

        while (true) {
            long now = System.currentTimeMillis();
            if (now > next) {
                next = now + mils;
                playSound();
            }

        }
    }

}

void genTone() {
    sample = new double[numSamples];
    generatedSnd = new byte[2 * numSamples];
    int rate = numSamples / period;

    for (int i = 0; i < numSamples; ++i) {
        if (i % rate == 0) {
            System.out.println("+++ Create tone " + i);

            int j = 0;
            for (j = 0; j < pulseLength; j++) {

                sample[i + j] = Math.sin(2 * Math.PI * (i + j)
                        / (sampleRate / freqOfTone));
                System.out.println("+++ SAMPLE " + (i + j) + " "
                        + sample[i + j]);
            }
            i = i + j;
        }
    }

    // convert to 16 bit pcm sound array
    // assumes the sample buffer is normalised.
    int idx = 0;
    for (final double dVal : sample) {
        // scale to maximum amplitude
        final short val = (short) ((dVal * 32767));
        // in 16 bit wav PCM, first byte is the low order byte
        generatedSnd[idx++] = (byte) (val & 0x00ff);
        generatedSnd[idx++] = (byte) ((val & 0xff00) >>> 8);

    }

}


void playSound() {
    System.out.println("+++ PLAY " );
    //audioTrack.stop();
    //audioTrack.setPlaybackHeadPosition(0);
    final AudioTrack audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, sampleRate, AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT, generatedSnd.length, AudioTrack.MODE_STATIC);
    audioTrack.write(generatedSnd, 0, generatedSnd.length);
    audioTrack.play();
}

这是完整的错误:

01-02 18:24:45.035: E/AndroidRuntime(6599): FATAL EXCEPTION: AsyncTask #1
01-02 18:24:45.035: E/AndroidRuntime(6599): java.lang.RuntimeException: An error occured while executing doInBackground()
01-02 18:24:45.035: E/AndroidRuntime(6599):     at android.os.AsyncTask$3.done(AsyncTask.java:200)
01-02 18:24:45.035: E/AndroidRuntime(6599):     at java.util.concurrent.FutureTask$Sync.innerSetException(FutureTask.java:274)
01-02 18:24:45.035: E/AndroidRuntime(6599):     at java.util.concurrent.FutureTask.setException(FutureTask.java:125)
01-02 18:24:45.035: E/AndroidRuntime(6599):     at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:308)
01-02 18:24:45.035: E/AndroidRuntime(6599):     at java.util.concurrent.FutureTask.run(FutureTask.java:138)
01-02 18:24:45.035: E/AndroidRuntime(6599):     at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1088)
01-02 18:24:45.035: E/AndroidRuntime(6599):     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:581)
01-02 18:24:45.035: E/AndroidRuntime(6599):     at java.lang.Thread.run(Thread.java:1019)
01-02 18:24:45.035: E/AndroidRuntime(6599): Caused by: java.lang.IllegalStateException: play() called on uninitialized AudioTrack.
01-02 18:24:45.035: E/AndroidRuntime(6599):     at android.media.AudioTrack.play(AudioTrack.java:824)
01-02 18:24:45.035: E/AndroidRuntime(6599):     at uk.co.moonsit.signals.DisplayBowieActivity.playSound(DisplayBowieActivity.java:164)
01-02 18:24:45.035: E/AndroidRuntime(6599):     at uk.co.moonsit.signals.DisplayBowieActivity$SoundGen.doInBackground(DisplayBowieActivity.java:90)
01-02 18:24:45.035: E/AndroidRuntime(6599):     at uk.co.moonsit.signals.DisplayBowieActivity$SoundGen.doInBackground(DisplayBowieActivity.java:1)
01-02 18:24:45.035: E/AndroidRuntime(6599):     at android.os.AsyncTask$2.call(AsyncTask.java:185)
01-02 18:24:45.035: E/AndroidRuntime(6599):     at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:306)
01-02 18:24:45.035: E/AndroidRuntime(6599):     ... 4 more

【问题讨论】:

标签: java android multithreading android-asynctask audiotrack


【解决方案1】:

AudioTracks 用完了,在你的情况下是 20 个,在我的 Nexus4 上是 30 个,这给了我:

175-5975/? E/AudioFlinger﹕ no more track names available

一种解决方案 - 使用您已经拥有的全局 audioTrack 对象,并将其设为 null 并在每次播放时创建:

void playSound() {
    System.out.println("+++ PLAY ");

    //if audioTrack has been initialised, first, release any resources
    //then null it
    if (audioTrack != null) {
        audioTrack.release();
        audioTrack = null;
    }

    //now create it again, note: use global audioTrack,
    //that means remove "final AudioTrack" here
    audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, sampleRate, AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT, generatedSnd.length, AudioTrack.MODE_STATIC);

    audioTrack.write(generatedSnd, 0, generatedSnd.length);
    audioTrack.play();
}

【讨论】:

  • 谢谢,成功了。虽然实际上我想重复播放同一首曲目。我确实尝试只创建一次,但它只播放了一次。我错过了 stop() 和 reloadStaticData(),所以现在我创建了一次,它会重复播放相同的曲目。
【解决方案2】:

您的 AudioTrack 被创建了 20 多次。每个设备都有一个允许的最大数量的 AudioTrack。所以只需使用一个并像这样在全局范围内初始化它:

final AudioTrack audioTrack = null;
void playSound() {
audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, sampleRate, AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT, generatedSnd.length, AudioTrack.MODE_STATIC);
audioTrack.write(generatedSnd, 0, generatedSnd.length);
audioTrack.play();
}

【讨论】:

  • 我相信你不能修改最终变量。
猜你喜欢
  • 1970-01-01
  • 2017-03-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多