Reputation: 3870
I'm using AudioTrack
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);
}
samples.add(sample);
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.MODE_STATIC);
audioTrack.write(generatedSnd, 0, generatedSnd.length);
audioTrack.play();
Does anyone have any idea? Thanks!
Upvotes: 9
Views: 1613
Reputation: 3870
It's likely the garbage collection causing this problem. I was writing this code in a method returning immediately, as audioTrack
object will lose the reference to it. If garbage collection happens during the playback, audioTrack
will be finalized and stops playing tones. Thus this issue happens occasionally, depending on how active the GC is when playing tones.
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;
}
MediaPlayer
also has this pitfall, and is how I found the problem since it will write log that it's finalized before released.
Upvotes: 0
Reputation: 3497
You are using AudioTrack.MODE_STATIC that is meant for short sounds and low-latency requirements while you should use AudioTrack.MODE_STREAM. AudioTrack.MODE_STREAM is meant for longer streams, but I do not know how long your samples are. So you can try and change AudioTrack:
audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC,
sampleRate, AudioFormat.CHANNEL_OUT_MONO,
AudioFormat.ENCODING_PCM_16BIT, generatedSnd.length,
AudioTrack.MODE_STREAM);
Also The AudioTrack requires the buffer size in bytes, a short needs to be multiplied by two to calculate the correct amount of required bytes. You could hack it in like this :
audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC,
sampleRate, AudioFormat.CHANNEL_OUT_MONO,
AudioFormat.ENCODING_PCM_16BIT, generatedSnd.length*2,
AudioTrack.MODE_STREAM);
Upvotes: 3