Romulus Urakagi Ts'ai Romulus Urakagi Ts'ai - 6 months ago 34
Android Question

Android AudioTrack does not play all samples

I'm using

to play a sequence of sine waves, but when I run it on my HTC M9, it plays only part of the samples, and how long it will play is random. e. g. I have 20 tones to play, but it only plays like 2 to 17.5 tones of them. And yes it even will stop in middle of a tone.

Here is my code, from another answer:

ArrayList<double[]> samples = new ArrayList<>();
int numSamples = 0;
for (final ToneSegment seg : sequence) {
int num = seg.getDuration() * sampleRate / 1000;
double[] sample = new double[num];
for (int i = 0; i < num; ++i) {
sample[i] = Math.sin(2 * Math.PI * i * seg.getPitch() / sampleRate);
numSamples += num;

byte generatedSnd[] = new byte[2 * numSamples];
int idx = 0;
for (double[] sample : samples) {
for (final double dVal : sample) {
final short val = (short) ((dVal * 32767));
generatedSnd[idx++] = (byte) (val & 0x00ff);
generatedSnd[idx++] = (byte) ((val & 0xff00) >>> 8);

audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC,
sampleRate, AudioFormat.CHANNEL_OUT_MONO,
AudioFormat.ENCODING_PCM_16BIT, generatedSnd.length,
audioTrack.write(generatedSnd, 0, generatedSnd.length);;

Does anyone have any idea? Thanks!


It's likely the garbage collection causing this problem. I was writing this code in a method returning soon, so audioTrack object has no reference to it. If garbage collection happens during the playback, audioTrack will be finalized and stops playing tones. MediaPlayer also has this pitfall.

So I need to keep the AudioTrack object reference until the playback ends. I think there are many ways to do this, but finally I use the simplest way:

class Player {
    private static AudioTrack sAudioTrack;